diff --git a/src/main/java/org/etsi/osl/tmf/pim637/api/HubApi.java b/src/main/java/org/etsi/osl/tmf/pim637/api/HubApi.java index 7dc3b86aea3df45469e25725451605e52133e6c8..8a1652a7d969451b88349472e8dcd9d2e056bf5c 100644 --- a/src/main/java/org/etsi/osl/tmf/pim637/api/HubApi.java +++ b/src/main/java/org/etsi/osl/tmf/pim637/api/HubApi.java @@ -5,7 +5,6 @@ */ package org.etsi.osl.tmf.pim637.api; -import org.etsi.osl.tmf.pim637.model.Error; import org.etsi.osl.tmf.pim637.model.EventSubscription; import org.etsi.osl.tmf.pim637.model.EventSubscriptionInput; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/org/etsi/osl/tmf/pim637/api/ListenerApi.java b/src/main/java/org/etsi/osl/tmf/pim637/api/ListenerApi.java index 8ea75df1e1c1685af62bef92deb90df4eee25ce9..5a63d8230b062a68e48fd87347b79941ed254e8e 100644 --- a/src/main/java/org/etsi/osl/tmf/pim637/api/ListenerApi.java +++ b/src/main/java/org/etsi/osl/tmf/pim637/api/ListenerApi.java @@ -5,7 +5,6 @@ */ package org.etsi.osl.tmf.pim637.api; -import org.etsi.osl.tmf.pim637.model.Error; import org.etsi.osl.tmf.pim637.model.EventSubscription; import org.etsi.osl.tmf.pim637.model.ProductAttributeValueChangeEvent; import org.etsi.osl.tmf.pim637.model.ProductBatchEvent; diff --git a/src/main/java/org/etsi/osl/tmf/pim637/api/ProductApi.java b/src/main/java/org/etsi/osl/tmf/pim637/api/ProductApi.java index c4f9f782563f7131a31f0a781f030f7310203880..0631e1961838c67b81f62af7b69f517e3b5a5906 100644 --- a/src/main/java/org/etsi/osl/tmf/pim637/api/ProductApi.java +++ b/src/main/java/org/etsi/osl/tmf/pim637/api/ProductApi.java @@ -6,7 +6,6 @@ package org.etsi.osl.tmf.pim637.api; import java.util.List; -import org.etsi.osl.tmf.pim637.model.Error; import org.etsi.osl.tmf.pim637.model.Product; import org.etsi.osl.tmf.pim637.model.ProductCreate; import org.etsi.osl.tmf.pim637.model.ProductUpdate; diff --git a/src/main/java/org/etsi/osl/tmf/scm633/api/HubApi.java b/src/main/java/org/etsi/osl/tmf/scm633/api/HubApi.java index cd7d1306f137b198a673c0248fbb222efc70e9f8..1f0678cb162e949b86f27944c3e772e2a3ea3a19 100644 --- a/src/main/java/org/etsi/osl/tmf/scm633/api/HubApi.java +++ b/src/main/java/org/etsi/osl/tmf/scm633/api/HubApi.java @@ -27,6 +27,7 @@ package org.etsi.osl.tmf.scm633.api; import org.etsi.osl.tmf.scm633.model.EventSubscription; import org.etsi.osl.tmf.scm633.model.EventSubscriptionInput; import org.springframework.http.ResponseEntity; +import java.util.List; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -74,4 +75,16 @@ public interface HubApi { method = RequestMethod.DELETE) ResponseEntity unregisterListener(@Parameter(description = "The id of the registered listener",required=true) @PathVariable("id") String id); + @Operation(summary = "Get all registered listeners", operationId = "getListeners", description = "Retrieves all registered event subscriptions", tags={ "events subscription", }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success" ), + @ApiResponse(responseCode = "400", description = "Bad Request" ), + @ApiResponse(responseCode = "401", description = "Unauthorized" ), + @ApiResponse(responseCode = "403", description = "Forbidden" ), + @ApiResponse(responseCode = "500", description = "Internal Server Error" ) }) + @RequestMapping(value = "/hub", + produces = { "application/json;charset=utf-8" }, + method = RequestMethod.GET) + ResponseEntity> getListeners(); + } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/api/HubApiController.java b/src/main/java/org/etsi/osl/tmf/scm633/api/HubApiController.java index 2d7ec59a96d552681641c23c97ab80f9fe3931d3..ce6adb20e6fe55db6d8fe5c06f14d097809859c9 100644 --- a/src/main/java/org/etsi/osl/tmf/scm633/api/HubApiController.java +++ b/src/main/java/org/etsi/osl/tmf/scm633/api/HubApiController.java @@ -20,18 +20,24 @@ package org.etsi.osl.tmf.scm633.api; import java.io.IOException; +import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; import org.etsi.osl.tmf.scm633.model.EventSubscription; import org.etsi.osl.tmf.scm633.model.EventSubscriptionInput; +import org.etsi.osl.tmf.scm633.reposervices.EventSubscriptionRepoService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import io.swagger.v3.oas.annotations.Parameter; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; @@ -46,6 +52,10 @@ public class HubApiController implements HubApi { private final ObjectMapper objectMapper; private final HttpServletRequest request; + + @Autowired + @Qualifier("scm633EventSubscriptionRepoService") + EventSubscriptionRepoService eventSubscriptionRepoService; @org.springframework.beans.factory.annotation.Autowired public HubApiController(ObjectMapper objectMapper, HttpServletRequest request) { @@ -53,23 +63,49 @@ public class HubApiController implements HubApi { this.request = request; } + @Override + @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'ROLE_USER')") public ResponseEntity registerListener(@Parameter(description = "Data containing the callback endpoint to deliver the information" ,required=true ) @Valid @RequestBody EventSubscriptionInput data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + EventSubscription eventSubscription = eventSubscriptionRepoService.addEventSubscription(data); + return new ResponseEntity<>(eventSubscription, HttpStatus.CREATED); + } catch (IllegalArgumentException e) { + log.error("Invalid input for listener registration: {}", e.getMessage()); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } catch (Exception e) { + log.error("Error registering listener", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override + @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'ROLE_USER')") + @RequestMapping(value = "/hub/{id}", method = RequestMethod.DELETE, produces = { "application/json;charset=utf-8" }) public ResponseEntity unregisterListener(@Parameter(description = "The id of the registered listener",required=true) @PathVariable("id") String id) { - String accept = request.getHeader("Accept"); - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + try { + EventSubscription existing = eventSubscriptionRepoService.findById(id); + if (existing == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + eventSubscriptionRepoService.deleteById(id); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } catch (Exception e) { + log.error("Error unregistering listener with id: " + id, e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + @Override + @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'ROLE_USER')") + public ResponseEntity> getListeners() { + try { + List eventSubscriptions = eventSubscriptionRepoService.findAll(); + return new ResponseEntity<>(eventSubscriptions, HttpStatus.OK); + } catch (Exception e) { + log.error("Error retrieving listeners", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + } } } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/api/ListenerApiController.java b/src/main/java/org/etsi/osl/tmf/scm633/api/ListenerApiController.java index 912e48f60ee5b99e8c07e10eda7185fb20c1456b..9f19fb8cefdf997dd16458833efa6e35946ec578 100644 --- a/src/main/java/org/etsi/osl/tmf/scm633/api/ListenerApiController.java +++ b/src/main/java/org/etsi/osl/tmf/scm633/api/ListenerApiController.java @@ -19,7 +19,7 @@ */ package org.etsi.osl.tmf.scm633.api; -import java.io.IOException; +import java.util.Optional; import com.fasterxml.jackson.databind.ObjectMapper; import org.etsi.osl.tmf.scm633.model.EventSubscription; @@ -64,186 +64,168 @@ public class ListenerApiController implements ListenerApi { this.request = request; } + public Optional getObjectMapper() { + return Optional.ofNullable(objectMapper); + } + + public Optional getRequest() { + return Optional.ofNullable(request); + } + + @Override public ResponseEntity listenToServiceCandidateChangeNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCandidateChangeNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCandidateChangeNotification: {}", data.getEventId()); + log.debug("ServiceCandidateChangeNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCandidateChangeNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceCandidateCreateNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCandidateCreateNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCandidateCreateNotification: {}", data.getEventId()); + log.debug("ServiceCandidateCreateNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCandidateCreateNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceCandidateDeleteNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCandidateDeleteNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCandidateDeleteNotification: {}", data.getEventId()); + log.debug("ServiceCandidateDeleteNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCandidateDeleteNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceCatalogBatchNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCatalogBatchNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCatalogBatchNotification: {}", data.getEventId()); + log.debug("ServiceCatalogBatchNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCatalogBatchNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceCatalogChangeNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCatalogChangeNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCatalogChangeNotification: {}", data.getEventId()); + log.debug("ServiceCatalogChangeNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCatalogChangeNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceCatalogCreateNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCatalogCreateNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCatalogCreateNotification: {}", data.getEventId()); + log.debug("ServiceCatalogCreateNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCatalogCreateNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceCatalogDeleteNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCatalogDeleteNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCatalogDeleteNotification: {}", data.getEventId()); + log.debug("ServiceCatalogDeleteNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCatalogDeleteNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceCategoryChangeNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCategoryChangeNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCategoryChangeNotification: {}", data.getEventId()); + log.debug("ServiceCategoryChangeNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCategoryChangeNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceCategoryCreateNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCategoryCreateNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCategoryCreateNotification: {}", data.getEventId()); + log.debug("ServiceCategoryCreateNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCategoryCreateNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceCategoryDeleteNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceCategoryDeleteNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceCategoryDeleteNotification: {}", data.getEventId()); + log.debug("ServiceCategoryDeleteNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceCategoryDeleteNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceSpecificationChangeNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceSpecificationChangeNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceSpecificationChangeNotification: {}", data.getEventId()); + log.debug("ServiceSpecificationChangeNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceSpecificationChangeNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceSpecificationCreateNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceSpecificationCreateNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceSpecificationCreateNotification: {}", data.getEventId()); + log.debug("ServiceSpecificationCreateNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceSpecificationCreateNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } + @Override public ResponseEntity listenToServiceSpecificationDeleteNotification(@Parameter(description = "The event data" ,required=true ) @Valid @RequestBody ServiceSpecificationDeleteNotification data) { - String accept = request.getHeader("Accept"); - if (accept != null && accept.contains("application/json")) { - try { - return new ResponseEntity(objectMapper.readValue("{ \"query\" : \"query\", \"callback\" : \"callback\", \"id\" : \"id\"}", EventSubscription.class), HttpStatus.NOT_IMPLEMENTED); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + try { + log.info("Received ServiceSpecificationDeleteNotification: {}", data.getEventId()); + log.debug("ServiceSpecificationDeleteNotification details: {}", data); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + log.error("Error processing ServiceSpecificationDeleteNotification", e); + return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); } } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceCatalogApiRouteBuilderEvents.java b/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceCatalogApiRouteBuilderEvents.java new file mode 100644 index 0000000000000000000000000000000000000000..630ad076225b97e968bf3a35d660a1d28f306e53 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/scm633/api/ServiceCatalogApiRouteBuilderEvents.java @@ -0,0 +1,164 @@ +/*- + * ========================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 java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.etsi.osl.centrallog.client.CLevel; +import org.etsi.osl.centrallog.client.CentralLogger; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogDeleteNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryDeleteNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationDeleteNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationChangeNotification; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +@Component +public class ServiceCatalogApiRouteBuilderEvents extends RouteBuilder { + + private static final transient Log logger = LogFactory.getLog(ServiceCatalogApiRouteBuilderEvents.class.getName()); + + @Value("${EVENT_SERVICE_CATALOG_CREATE}") + private String EVENT_SERVICE_CATALOG_CREATE = "direct:EVENT_SERVICE_CATALOG_CREATE"; + + @Value("${EVENT_SERVICE_CATALOG_DELETE}") + private String EVENT_SERVICE_CATALOG_DELETE = "direct:EVENT_SERVICE_CATALOG_DELETE"; + + @Value("${EVENT_SERVICE_CATEGORY_CREATE}") + private String EVENT_SERVICE_CATEGORY_CREATE = "direct:EVENT_SERVICE_CATEGORY_CREATE"; + + @Value("${EVENT_SERVICE_CATEGORY_DELETE}") + private String EVENT_SERVICE_CATEGORY_DELETE = "direct:EVENT_SERVICE_CATEGORY_DELETE"; + + @Value("${EVENT_SERVICE_SPECIFICATION_CREATE}") + private String EVENT_SERVICE_SPECIFICATION_CREATE = "direct:EVENT_SERVICE_SPECIFICATION_CREATE"; + + @Value("${EVENT_SERVICE_SPECIFICATION_DELETE}") + private String EVENT_SERVICE_SPECIFICATION_DELETE = "direct:EVENT_SERVICE_SPECIFICATION_DELETE"; + + @Value("${EVENT_SERVICE_SPECIFICATION_CHANGE}") + private String EVENT_SERVICE_SPECIFICATION_CHANGE = "direct:EVENT_SERVICE_SPECIFICATION_CHANGE"; + + @Autowired + private ApplicationContext context; + + @Autowired + private ProducerTemplate template; + + + @Autowired + private CentralLogger centralLogger; + + @Override + public void configure() throws Exception { + + } + + public void publishEvent(Object notification, String objId) { + + try { + String msgtopic = ""; + + if (notification instanceof ServiceCatalogCreateNotification) { + msgtopic = EVENT_SERVICE_CATALOG_CREATE; + } else if (notification instanceof ServiceCatalogDeleteNotification) { + msgtopic = EVENT_SERVICE_CATALOG_DELETE; + } else if (notification instanceof ServiceCategoryCreateNotification) { + msgtopic = EVENT_SERVICE_CATEGORY_CREATE; + } else if (notification instanceof ServiceCategoryDeleteNotification) { + msgtopic = EVENT_SERVICE_CATEGORY_DELETE; + } else if (notification instanceof ServiceSpecificationCreateNotification) { + msgtopic = EVENT_SERVICE_SPECIFICATION_CREATE; + } else if (notification instanceof ServiceSpecificationDeleteNotification) { + msgtopic = EVENT_SERVICE_SPECIFICATION_DELETE; + } else if (notification instanceof ServiceSpecificationChangeNotification) { + msgtopic = EVENT_SERVICE_SPECIFICATION_CHANGE; + } + + Map map = new HashMap<>(); + String eventId = null; + + if (notification instanceof ServiceCatalogCreateNotification) { + eventId = ((ServiceCatalogCreateNotification) notification).getEventId(); + } else if (notification instanceof ServiceCatalogDeleteNotification) { + eventId = ((ServiceCatalogDeleteNotification) notification).getEventId(); + } else if (notification instanceof ServiceCategoryCreateNotification) { + eventId = ((ServiceCategoryCreateNotification) notification).getEventId(); + } else if (notification instanceof ServiceCategoryDeleteNotification) { + eventId = ((ServiceCategoryDeleteNotification) notification).getEventId(); + } else if (notification instanceof ServiceSpecificationCreateNotification) { + eventId = ((ServiceSpecificationCreateNotification) notification).getEventId(); + } else if (notification instanceof ServiceSpecificationDeleteNotification) { + eventId = ((ServiceSpecificationDeleteNotification) notification).getEventId(); + } else if (notification instanceof ServiceSpecificationChangeNotification) { + eventId = ((ServiceSpecificationChangeNotification) notification).getEventId(); + } + + map.put("eventid", eventId); + map.put("objId", objId); + + String apayload = toJsonString(notification); + map.put("event", apayload); + + template.sendBodyAndHeaders(msgtopic, apayload, map); + + String msgtxt = "EVENT " + notification.getClass().getName() + " sent"; + logger.info(msgtxt); + centralLogger.log(CLevel.INFO, msgtxt, compname()); + + } catch (Exception e) { + //e.printStackTrace(); + logger.error("Cannot send Event to message bus. " + e.getMessage()); + } + } + + static String toJsonString(Object object) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new JavaTimeModule()); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return mapper.writeValueAsString(object); + } + + static T toJsonObj(String content, Class valueType) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new JavaTimeModule()); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return mapper.readValue(content, valueType); + } + + private String compname() { + return "ServiceCatalogApiRouteBuilderEvents"; + } +} \ No newline at end of file diff --git a/src/main/java/org/etsi/osl/tmf/scm633/repo/EventSubscriptionRepository.java b/src/main/java/org/etsi/osl/tmf/scm633/repo/EventSubscriptionRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..732bd912a122a5893308890079bc57d0b639c5bd --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/scm633/repo/EventSubscriptionRepository.java @@ -0,0 +1,37 @@ +/*- + * ========================LICENSE_START================================= + * org.etsi.osl.tmf.api + * %% + * Copyright (C) 2019 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.repo; + +import java.util.List; +import java.util.Optional; +import org.etsi.osl.tmf.scm633.model.EventSubscription; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +@Repository("scm633EventSubscriptionRepository") +public interface EventSubscriptionRepository extends CrudRepository, PagingAndSortingRepository { + + Optional findById(String id); + + void deleteById(String id); + + List findAll(); +} \ No newline at end of file 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 0affd75072fa4035b1fd0e8a2756209e072f7e70..f55b69bf52ddca25ef513e1cd6d0ca437fbef3c2 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 @@ -60,11 +60,14 @@ public class CatalogRepoService { @Autowired ServiceSpecificationRepoService specRepoService; - - public ServiceCatalog addCatalog(ServiceCatalog c) { + @Autowired + ServiceCatalogNotificationService serviceCatalogNotificationService; - return this.catalogRepo.save(c); + public ServiceCatalog addCatalog(ServiceCatalog c) { + ServiceCatalog savedCatalog = this.catalogRepo.save(c); + serviceCatalogNotificationService.publishServiceCatalogCreateNotification(savedCatalog); + return savedCatalog; } public ServiceCatalog addCatalog(@Valid ServiceCatalogCreate serviceCat) { @@ -72,7 +75,9 @@ public class CatalogRepoService { ServiceCatalog sc = new ServiceCatalog(); sc = updateCatalogDataFromAPICall(sc, serviceCat); - return this.catalogRepo.save(sc); + ServiceCatalog savedCatalog = this.catalogRepo.save(sc); + serviceCatalogNotificationService.publishServiceCatalogCreateNotification(savedCatalog); + return savedCatalog; } public String findAllEager() { @@ -163,9 +168,12 @@ public class CatalogRepoService { public Void deleteById(String id) { Optional optionalCat = this.catalogRepo.findByUuid(id); - this.catalogRepo.delete(optionalCat.get()); + if (optionalCat.isPresent()) { + ServiceCatalog catalogToDelete = optionalCat.get(); + serviceCatalogNotificationService.publishServiceCatalogDeleteNotification(catalogToDelete); + this.catalogRepo.delete(catalogToDelete); + } return null; - } public ServiceCatalog updateCatalog(String id, ServiceCatalogUpdate serviceCatalog) { 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 9767f0df2faa4d987c8ca2c3258c35af04f1e50e..a8277db8b763cd41fc131d4c5f4e4f3adecbda05 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 @@ -55,6 +55,9 @@ public class CategoryRepoService { private final CategoriesRepository categsRepo; private final CandidateRepository candidateRepo; + + @Autowired + private ServiceCategoryNotificationService serviceCategoryNotificationService; @Autowired @@ -64,8 +67,9 @@ public class CategoryRepoService { } public ServiceCategory addCategory(ServiceCategory c) { - - return this.getCategsRepo().save( c ); + ServiceCategory savedCategory = this.getCategsRepo().save(c); + serviceCategoryNotificationService.publishServiceCategoryCreateNotification(savedCategory); + return savedCategory; } public ServiceCategory addCategory(@Valid ServiceCategoryCreate serviceCategory) { @@ -73,7 +77,9 @@ public class CategoryRepoService { ServiceCategory sc = new ServiceCategory() ; sc = updateCategoryDataFromAPICall(sc, serviceCategory); - return this.getCategsRepo().save( sc ); + ServiceCategory savedCategory = this.getCategsRepo().save(sc); + serviceCategoryNotificationService.publishServiceCategoryCreateNotification(savedCategory); + return savedCategory; } @@ -165,17 +171,25 @@ public class CategoryRepoService { public boolean deleteById(String id) { Optional optionalCat = this.getCategsRepo().findByUuid( id ); - if ( optionalCat.get().getCategoryObj().size()>0 ) { + + // Check if category exists + if (!optionalCat.isPresent()) { + return false; // Category not found + } + + ServiceCategory category = optionalCat.get(); + + if ( category.getCategoryObj().size()>0 ) { return false; //has children } - if ( optionalCat.get().getParentId() != null ) { - ServiceCategory parentCat = (this.getCategsRepo().findByUuid( optionalCat.get().getParentId() )).get(); + if ( category.getParentId() != null ) { + ServiceCategory parentCat = (this.getCategsRepo().findByUuid( category.getParentId() )).get(); //remove from parent category for (ServiceCategory ss : parentCat.getCategoryObj()) { - if ( ss.getId() == optionalCat.get().getId() ) { + if ( ss.getId() == category.getId() ) { parentCat.getCategoryObj().remove(ss); break; } @@ -183,8 +197,8 @@ public class CategoryRepoService { parentCat = this.getCategsRepo().save(parentCat); } - - this.getCategsRepo().delete( optionalCat.get()); + serviceCategoryNotificationService.publishServiceCategoryDeleteNotification(category); + this.getCategsRepo().delete(category); return true; } diff --git a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/EventSubscriptionRepoService.java b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/EventSubscriptionRepoService.java new file mode 100644 index 0000000000000000000000000000000000000000..b47eb5490cf875ad9ea6013fffc831f2a5c8f676 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/EventSubscriptionRepoService.java @@ -0,0 +1,72 @@ +/*- + * ========================LICENSE_START================================= + * org.etsi.osl.tmf.api + * %% + * Copyright (C) 2019 - 2021 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.reposervices; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.etsi.osl.tmf.scm633.model.EventSubscription; +import org.etsi.osl.tmf.scm633.model.EventSubscriptionInput; +import org.etsi.osl.tmf.scm633.repo.EventSubscriptionRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import jakarta.validation.Valid; + +@Service("scm633EventSubscriptionRepoService") +@Transactional +public class EventSubscriptionRepoService { + + @Autowired + @Qualifier("scm633EventSubscriptionRepository") + EventSubscriptionRepository eventSubscriptionRepo; + + public EventSubscription addEventSubscription(@Valid EventSubscriptionInput eventSubscriptionInput) { + if (eventSubscriptionInput.getCallback() == null || eventSubscriptionInput.getCallback().trim().isEmpty()) { + throw new IllegalArgumentException("Callback URL is required and cannot be empty"); + } + + EventSubscription eventSubscription = new EventSubscription(); + eventSubscription.setId(UUID.randomUUID().toString()); + eventSubscription.setCallback(eventSubscriptionInput.getCallback()); + eventSubscription.setQuery(eventSubscriptionInput.getQuery()); + + return this.eventSubscriptionRepo.save(eventSubscription); + } + + public EventSubscription findById(String id) { + Optional optionalEventSubscription = this.eventSubscriptionRepo.findById(id); + return optionalEventSubscription.orElse(null); + } + + public void deleteById(String id) { + Optional optionalEventSubscription = this.eventSubscriptionRepo.findById(id); + if (optionalEventSubscription.isPresent()) { + this.eventSubscriptionRepo.delete(optionalEventSubscription.get()); + } + } + + public List findAll() { + return (List) this.eventSubscriptionRepo.findAll(); + } +} \ No newline at end of file diff --git a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceCatalogCallbackService.java b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceCatalogCallbackService.java new file mode 100644 index 0000000000000000000000000000000000000000..57d9ea47dadc1943b0a2c92f2ef6cea76b8a8d15 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceCatalogCallbackService.java @@ -0,0 +1,361 @@ +/*- + * ========================LICENSE_START================================= + * org.etsi.osl.tmf.api + * %% + * Copyright (C) 2019 - 2021 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.reposervices; + +import java.util.List; +import org.etsi.osl.tmf.scm633.model.EventSubscription; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogDeleteNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryDeleteNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationChangeNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationDeleteNotification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class ServiceCatalogCallbackService { + + private static final Logger logger = LoggerFactory.getLogger(ServiceCatalogCallbackService.class); + + @Autowired + @Qualifier("scm633EventSubscriptionRepoService") + private EventSubscriptionRepoService notificationSubscriptionRepoService; + + @Autowired + private RestTemplate restTemplate; + + /** + * Send service catalog create notification to all registered callback URLs + * @param serviceCatalogCreateNotification The service catalog create notification to send + */ + public void sendServiceCatalogCreateCallback(ServiceCatalogCreateNotification serviceCatalogCreateNotification) { + List subscriptions = notificationSubscriptionRepoService.findAll(); + + for (EventSubscription subscription : subscriptions) { + if (shouldNotifySubscription(subscription, "serviceCatalogCreateNotification")) { + sendServiceCatalogCreateNotificationToCallback(subscription.getCallback(), serviceCatalogCreateNotification); + } + } + } + + /** + * Send service catalog delete notification to all registered callback URLs + * @param serviceCatalogDeleteEvent The service catalog delete notification to send + */ + public void sendServiceCatalogDeleteCallback(ServiceCatalogDeleteNotification serviceCatalogDeleteNotification) { + List subscriptions = notificationSubscriptionRepoService.findAll(); + + for (EventSubscription subscription : subscriptions) { + if (shouldNotifySubscription(subscription, "serviceCatalogDeleteNotification")) { + sendServiceCatalogDeleteNotificationToCallback(subscription.getCallback(), serviceCatalogDeleteNotification); + } + } + } + + /** + * Send service catalog create notification to a specific callback URL + * @param callbackUrl The callback URL to send to + * @param notification The service catalog create notification + */ + private void sendServiceCatalogCreateNotificationToCallback(String callbackUrl, ServiceCatalogCreateNotification notification) { + try { + String url = buildCallbackUrl(callbackUrl, "/listener/serviceCatalogCreateNotification"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(notification, headers); + + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.POST, entity, String.class); + + logger.info("Successfully sent service catalog create notification to callback URL: {} - Response: {}", + url, response.getStatusCode()); + + } catch (Exception e) { + logger.error("Failed to send service catalog create notification to callback URL: {}", callbackUrl, e); + } + } + + /** + * Send service catalog delete notification to a specific callback URL + * @param callbackUrl The callback URL to send to + * @param notification The service catalog delete notification + */ + private void sendServiceCatalogDeleteNotificationToCallback(String callbackUrl, ServiceCatalogDeleteNotification notification) { + try { + String url = buildCallbackUrl(callbackUrl, "/listener/serviceCatalogDeleteNotification"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(notification, headers); + + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.POST, entity, String.class); + + logger.info("Successfully sent service catalog delete notification to callback URL: {} - Response: {}", + url, response.getStatusCode()); + + } catch (Exception e) { + logger.error("Failed to send service catalog delete notification to callback URL: {}", callbackUrl, e); + } + } + + /** + * Build the full callback URL with the listener endpoint + * @param baseUrl The base callback URL + * @param listenerPath The listener path to append + * @return The complete callback URL + */ + private String buildCallbackUrl(String baseUrl, String listenerPath) { + if (baseUrl.endsWith("/")) { + return baseUrl.substring(0, baseUrl.length() - 1) + listenerPath; + } else { + return baseUrl + listenerPath; + } + } + + /** + * Send service category create notification to all registered callback URLs + * @param serviceCategoryCreateNotification The service category create notification to send + */ + public void sendServiceCategoryCreateCallback(ServiceCategoryCreateNotification serviceCategoryCreateNotification) { + List subscriptions = notificationSubscriptionRepoService.findAll(); + + for (EventSubscription subscription : subscriptions) { + if (shouldNotifySubscription(subscription, "serviceCategoryCreateNotification")) { + sendServiceCategoryCreateNotificationToCallback(subscription.getCallback(), serviceCategoryCreateNotification); + } + } + } + + /** + * Send service category delete notification to all registered callback URLs + * @param serviceCategoryDeleteNotification The service category delete notification to send + */ + public void sendServiceCategoryDeleteCallback(ServiceCategoryDeleteNotification serviceCategoryDeleteNotification) { + List subscriptions = notificationSubscriptionRepoService.findAll(); + + for (EventSubscription subscription : subscriptions) { + if (shouldNotifySubscription(subscription, "serviceCategoryDeleteNotification")) { + sendServiceCategoryDeleteNotificationToCallback(subscription.getCallback(), serviceCategoryDeleteNotification); + } + } + } + + /** + * Send service specification create notification to all registered callback URLs + * @param serviceSpecificationCreateNotification The service specification create notification to send + */ + public void sendServiceSpecificationCreateCallback(ServiceSpecificationCreateNotification serviceSpecificationCreateNotification) { + List subscriptions = notificationSubscriptionRepoService.findAll(); + + for (EventSubscription subscription : subscriptions) { + if (shouldNotifySubscription(subscription, "serviceSpecificationCreateNotification")) { + sendServiceSpecificationCreateNotificationToCallback(subscription.getCallback(), serviceSpecificationCreateNotification); + } + } + } + + /** + * Send service specification delete notification to all registered callback URLs + * @param serviceSpecificationDeleteNotification The service specification delete notification to send + */ + public void sendServiceSpecificationDeleteCallback(ServiceSpecificationDeleteNotification serviceSpecificationDeleteNotification) { + List subscriptions = notificationSubscriptionRepoService.findAll(); + + for (EventSubscription subscription : subscriptions) { + if (shouldNotifySubscription(subscription, "serviceSpecificationDeleteNotification")) { + sendServiceSpecificationDeleteNotificationToCallback(subscription.getCallback(), serviceSpecificationDeleteNotification); + } + } + } + + /** + * Send service specification change notification to all registered callback URLs + * @param serviceSpecificationChangeNotification The service specification change notification to send + */ + public void sendServiceSpecificationChangeCallback(ServiceSpecificationChangeNotification serviceSpecificationChangeNotification) { + List subscriptions = notificationSubscriptionRepoService.findAll(); + + for (EventSubscription subscription : subscriptions) { + if (shouldNotifySubscription(subscription, "serviceSpecificationChangeNotification")) { + sendServiceSpecificationChangeNotificationToCallback(subscription.getCallback(), serviceSpecificationChangeNotification); + } + } + } + + /** + * Send service category create notification to a specific callback URL + * @param callbackUrl The callback URL to send to + * @param notification The service category create notification + */ + private void sendServiceCategoryCreateNotificationToCallback(String callbackUrl, ServiceCategoryCreateNotification notification) { + try { + String url = buildCallbackUrl(callbackUrl, "/listener/serviceCategoryCreateNotification"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(notification, headers); + + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.POST, entity, String.class); + + logger.info("Successfully sent service category create notification to callback URL: {} - Response: {}", + url, response.getStatusCode()); + + } catch (Exception e) { + logger.error("Failed to send service category create notification to callback URL: {}", callbackUrl, e); + } + } + + /** + * Send service category delete notification to a specific callback URL + * @param callbackUrl The callback URL to send to + * @param notification The service category delete notification + */ + private void sendServiceCategoryDeleteNotificationToCallback(String callbackUrl, ServiceCategoryDeleteNotification notification) { + try { + String url = buildCallbackUrl(callbackUrl, "/listener/serviceCategoryDeleteNotification"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(notification, headers); + + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.POST, entity, String.class); + + logger.info("Successfully sent service category delete notification to callback URL: {} - Response: {}", + url, response.getStatusCode()); + + } catch (Exception e) { + logger.error("Failed to send service category delete notification to callback URL: {}", callbackUrl, e); + } + } + + /** + * Send service specification create notification to a specific callback URL + * @param callbackUrl The callback URL to send to + * @param notification The service specification create notification + */ + private void sendServiceSpecificationCreateNotificationToCallback(String callbackUrl, ServiceSpecificationCreateNotification notification) { + try { + String url = buildCallbackUrl(callbackUrl, "/listener/serviceSpecificationCreateNotification"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(notification, headers); + + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.POST, entity, String.class); + + logger.info("Successfully sent service specification create notification to callback URL: {} - Response: {}", + url, response.getStatusCode()); + + } catch (Exception e) { + logger.error("Failed to send service specification create notification to callback URL: {}", callbackUrl, e); + } + } + + /** + * Send service specification delete notification to a specific callback URL + * @param callbackUrl The callback URL to send to + * @param notification The service specification delete notification + */ + private void sendServiceSpecificationDeleteNotificationToCallback(String callbackUrl, ServiceSpecificationDeleteNotification notification) { + try { + String url = buildCallbackUrl(callbackUrl, "/listener/serviceSpecificationDeleteNotification"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(notification, headers); + + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.POST, entity, String.class); + + logger.info("Successfully sent service specification delete notification to callback URL: {} - Response: {}", + url, response.getStatusCode()); + + } catch (Exception e) { + logger.error("Failed to send service specification delete notification to callback URL: {}", callbackUrl, e); + } + } + + /** + * Send service specification change notification to a specific callback URL + * @param callbackUrl The callback URL to send to + * @param notification The service specification change notification + */ + private void sendServiceSpecificationChangeNotificationToCallback(String callbackUrl, ServiceSpecificationChangeNotification notification) { + try { + String url = buildCallbackUrl(callbackUrl, "/listener/serviceSpecificationChangeNotification"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(notification, headers); + + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.POST, entity, String.class); + + logger.info("Successfully sent service specification change notification to callback URL: {} - Response: {}", + url, response.getStatusCode()); + + } catch (Exception e) { + logger.error("Failed to send service specification change notification to callback URL: {}", callbackUrl, e); + } + } + + /** + * Check if a subscription should be notified for a specific notification type + * @param subscription The notification subscription + * @param notificationType The notification type to check + * @return true if the subscription should be notified + */ + private boolean shouldNotifySubscription(EventSubscription subscription, String notificationType) { + // If no query is specified, notify all notifications + if (subscription.getQuery() == null || subscription.getQuery().trim().isEmpty()) { + return true; + } + + // Check if the query contains the notification type + String query = subscription.getQuery().toLowerCase(); + return query.contains("servicecatalog") || + query.contains("servicecategory") || + query.contains("servicespecification") || + query.contains(notificationType.toLowerCase()) || + query.contains("servicecatalog.create") || + query.contains("servicecatalog.delete") || + query.contains("servicecategory.create") || + query.contains("servicecategory.delete") || + query.contains("servicespecification.create") || + query.contains("servicespecification.delete") || + query.contains("servicespecification.change"); + } +} \ No newline at end of file diff --git a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceCatalogNotificationService.java b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceCatalogNotificationService.java new file mode 100644 index 0000000000000000000000000000000000000000..dc33044e21aca1fcacf34eb0f4fe90d8b1ca4927 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceCatalogNotificationService.java @@ -0,0 +1,129 @@ +/*- + * ========================LICENSE_START================================= + * org.etsi.osl.tmf.api + * %% + * Copyright (C) 2019 - 2021 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.reposervices; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.UUID; + +import org.etsi.osl.tmf.scm633.api.ServiceCatalogApiRouteBuilderEvents; +import org.etsi.osl.tmf.scm633.model.ServiceCatalog; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogCreateEvent; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogDeleteEvent; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogDeleteNotification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class ServiceCatalogNotificationService { + + private static final Logger logger = LoggerFactory.getLogger(ServiceCatalogNotificationService.class); + + @Autowired + private ServiceCatalogApiRouteBuilderEvents eventPublisher; + + @Autowired + private ServiceCatalogCallbackService serviceCatalogCallbackService; + + /** + * Publish a service catalog create notification + * @param serviceCatalog The created service catalog + */ + public void publishServiceCatalogCreateNotification(ServiceCatalog serviceCatalog) { + try { + ServiceCatalogCreateNotification notification = createServiceCatalogCreateNotification(serviceCatalog); + eventPublisher.publishEvent(notification, serviceCatalog.getUuid()); + + // Send callbacks to registered subscribers + serviceCatalogCallbackService.sendServiceCatalogCreateCallback(notification); + + logger.info("Published service catalog create notification for service catalog ID: {}", serviceCatalog.getUuid()); + } catch (Exception e) { + logger.error("Error publishing service catalog create notification for service catalog ID: {}", serviceCatalog.getUuid(), e); + } + } + + /** + * Publish a service catalog delete notification + * @param serviceCatalog The deleted service catalog + */ + public void publishServiceCatalogDeleteNotification(ServiceCatalog serviceCatalog) { + try { + ServiceCatalogDeleteNotification notification = createServiceCatalogDeleteNotification(serviceCatalog); + eventPublisher.publishEvent(notification, serviceCatalog.getUuid()); + + // Send callbacks to registered subscribers + serviceCatalogCallbackService.sendServiceCatalogDeleteCallback(notification); + + logger.info("Published service catalog delete notification for service catalog ID: {}", serviceCatalog.getUuid()); + } catch (Exception e) { + logger.error("Error publishing service catalog delete notification for service catalog ID: {}", serviceCatalog.getUuid(), e); + } + } + + /** + * Create a service catalog create notification + * @param serviceCatalog The created service catalog + * @return ServiceCatalogCreateNotification + */ + private ServiceCatalogCreateNotification createServiceCatalogCreateNotification(ServiceCatalog serviceCatalog) { + ServiceCatalogCreateNotification notification = new ServiceCatalogCreateNotification(); + + // Set common notification properties + notification.setEventId(UUID.randomUUID().toString()); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + notification.setEventType(ServiceCatalogCreateNotification.class.getName()); + notification.setResourcePath("/serviceCatalogManagement/v4/serviceCatalog/" + serviceCatalog.getUuid()); + + // Create event + ServiceCatalogCreateEvent event = new ServiceCatalogCreateEvent(); + event.setServiceCatalog(serviceCatalog); + + notification.setEvent(event); + return notification; + } + + /** + * Create a service catalog delete notification + * @param serviceCatalog The deleted service catalog + * @return ServiceCatalogDeleteNotification + */ + private ServiceCatalogDeleteNotification createServiceCatalogDeleteNotification(ServiceCatalog serviceCatalog) { + ServiceCatalogDeleteNotification notification = new ServiceCatalogDeleteNotification(); + + // Set common notification properties + notification.setEventId(UUID.randomUUID().toString()); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + notification.setEventType(ServiceCatalogDeleteNotification.class.getName()); + notification.setResourcePath("/serviceCatalogManagement/v4/serviceCatalog/" + serviceCatalog.getUuid()); + + // Create event + ServiceCatalogDeleteEvent event = new ServiceCatalogDeleteEvent(); + event.setServiceCatalog(serviceCatalog); + + notification.setEvent(event); + return notification; + } +} \ No newline at end of file diff --git a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceCategoryNotificationService.java b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceCategoryNotificationService.java new file mode 100644 index 0000000000000000000000000000000000000000..9d36b82e9d9880e8af643bfa709d2cdb1135464f --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceCategoryNotificationService.java @@ -0,0 +1,129 @@ +/*- + * ========================LICENSE_START================================= + * org.etsi.osl.tmf.api + * %% + * Copyright (C) 2019 - 2021 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.reposervices; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.UUID; + +import org.etsi.osl.tmf.scm633.api.ServiceCatalogApiRouteBuilderEvents; +import org.etsi.osl.tmf.scm633.model.ServiceCategory; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreateEvent; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryDeleteEvent; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryDeleteNotification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class ServiceCategoryNotificationService { + + private static final Logger logger = LoggerFactory.getLogger(ServiceCategoryNotificationService.class); + + @Autowired + private ServiceCatalogApiRouteBuilderEvents eventPublisher; + + @Autowired + private ServiceCatalogCallbackService serviceCatalogCallbackService; + + /** + * Publish a service category create notification + * @param serviceCategory The created service category + */ + public void publishServiceCategoryCreateNotification(ServiceCategory serviceCategory) { + try { + ServiceCategoryCreateNotification notification = createServiceCategoryCreateNotification(serviceCategory); + eventPublisher.publishEvent(notification, serviceCategory.getUuid()); + + // Send callbacks to registered subscribers + serviceCatalogCallbackService.sendServiceCategoryCreateCallback(notification); + + logger.info("Published service category create notification for service category ID: {}", serviceCategory.getUuid()); + } catch (Exception e) { + logger.error("Error publishing service category create notification for service category ID: {}", serviceCategory.getUuid(), e); + } + } + + /** + * Publish a service category delete notification + * @param serviceCategory The deleted service category + */ + public void publishServiceCategoryDeleteNotification(ServiceCategory serviceCategory) { + try { + ServiceCategoryDeleteNotification notification = createServiceCategoryDeleteNotification(serviceCategory); + eventPublisher.publishEvent(notification, serviceCategory.getUuid()); + + // Send callbacks to registered subscribers + serviceCatalogCallbackService.sendServiceCategoryDeleteCallback(notification); + + logger.info("Published service category delete notification for service category ID: {}", serviceCategory.getUuid()); + } catch (Exception e) { + logger.error("Error publishing service category delete notification for service category ID: {}", serviceCategory.getUuid(), e); + } + } + + /** + * Create a service category create notification + * @param serviceCategory The created service category + * @return ServiceCategoryCreateNotification + */ + private ServiceCategoryCreateNotification createServiceCategoryCreateNotification(ServiceCategory serviceCategory) { + ServiceCategoryCreateNotification notification = new ServiceCategoryCreateNotification(); + + // Set common notification properties + notification.setEventId(UUID.randomUUID().toString()); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + notification.setEventType(ServiceCategoryCreateNotification.class.getName()); + notification.setResourcePath("/serviceCatalogManagement/v4/serviceCategory/" + serviceCategory.getUuid()); + + // Create event + ServiceCategoryCreateEvent event = new ServiceCategoryCreateEvent(); + event.setServiceCategory(serviceCategory); + + notification.setEvent(event); + return notification; + } + + /** + * Create a service category delete notification + * @param serviceCategory The deleted service category + * @return ServiceCategoryDeleteNotification + */ + private ServiceCategoryDeleteNotification createServiceCategoryDeleteNotification(ServiceCategory serviceCategory) { + ServiceCategoryDeleteNotification notification = new ServiceCategoryDeleteNotification(); + + // Set common notification properties + notification.setEventId(UUID.randomUUID().toString()); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + notification.setEventType(ServiceCategoryDeleteNotification.class.getName()); + notification.setResourcePath("/serviceCatalogManagement/v4/serviceCategory/" + serviceCategory.getUuid()); + + // Create event + ServiceCategoryDeleteEvent event = new ServiceCategoryDeleteEvent(); + event.setServiceCategory(serviceCategory); + + notification.setEvent(event); + return notification; + } +} \ No newline at end of file diff --git a/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceSpecificationNotificationService.java b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceSpecificationNotificationService.java new file mode 100644 index 0000000000000000000000000000000000000000..6f5c7db481f48f39e78a2727da0a7cc62fbc66f4 --- /dev/null +++ b/src/main/java/org/etsi/osl/tmf/scm633/reposervices/ServiceSpecificationNotificationService.java @@ -0,0 +1,171 @@ +/*- + * ========================LICENSE_START================================= + * org.etsi.osl.tmf.api + * %% + * Copyright (C) 2019 - 2021 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.reposervices; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.UUID; + +import org.etsi.osl.tmf.scm633.api.ServiceCatalogApiRouteBuilderEvents; +import org.etsi.osl.tmf.scm633.model.ServiceSpecification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationChangeEvent; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationChangeNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreateEvent; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationDeleteEvent; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationDeleteNotification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class ServiceSpecificationNotificationService { + + private static final Logger logger = LoggerFactory.getLogger(ServiceSpecificationNotificationService.class); + + @Autowired + private ServiceCatalogApiRouteBuilderEvents eventPublisher; + + @Autowired + private ServiceCatalogCallbackService serviceCatalogCallbackService; + + /** + * Publish a service specification create notification + * @param serviceSpecification The created service specification + */ + public void publishServiceSpecificationCreateNotification(ServiceSpecification serviceSpecification) { + try { + ServiceSpecificationCreateNotification notification = createServiceSpecificationCreateNotification(serviceSpecification); + eventPublisher.publishEvent(notification, serviceSpecification.getUuid()); + + // Send callbacks to registered subscribers + serviceCatalogCallbackService.sendServiceSpecificationCreateCallback(notification); + + logger.info("Published service specification create notification for service specification ID: {}", serviceSpecification.getUuid()); + } catch (Exception e) { + logger.error("Error publishing service specification create notification for service specification ID: {}", serviceSpecification.getUuid(), e); + } + } + + /** + * Publish a service specification delete notification + * @param serviceSpecification The deleted service specification + */ + public void publishServiceSpecificationDeleteNotification(ServiceSpecification serviceSpecification) { + try { + ServiceSpecificationDeleteNotification notification = createServiceSpecificationDeleteNotification(serviceSpecification); + eventPublisher.publishEvent(notification, serviceSpecification.getUuid()); + + // Send callbacks to registered subscribers + serviceCatalogCallbackService.sendServiceSpecificationDeleteCallback(notification); + + logger.info("Published service specification delete notification for service specification ID: {}", serviceSpecification.getUuid()); + } catch (Exception e) { + logger.error("Error publishing service specification delete notification for service specification ID: {}", serviceSpecification.getUuid(), e); + } + } + + /** + * Publish a service specification change notification + * @param serviceSpecification The changed service specification + */ + public void publishServiceSpecificationChangeNotification(ServiceSpecification serviceSpecification) { + try { + ServiceSpecificationChangeNotification notification = createServiceSpecificationChangeNotification(serviceSpecification); + eventPublisher.publishEvent(notification, serviceSpecification.getUuid()); + + // Send callbacks to registered subscribers + serviceCatalogCallbackService.sendServiceSpecificationChangeCallback(notification); + + logger.info("Published service specification change notification for service specification ID: {}", serviceSpecification.getUuid()); + } catch (Exception e) { + logger.error("Error publishing service specification change notification for service specification ID: {}", serviceSpecification.getUuid(), e); + } + } + + /** + * Create a service specification create notification + * @param serviceSpecification The created service specification + * @return ServiceSpecificationCreateNotification + */ + private ServiceSpecificationCreateNotification createServiceSpecificationCreateNotification(ServiceSpecification serviceSpecification) { + ServiceSpecificationCreateNotification notification = new ServiceSpecificationCreateNotification(); + + // Set common notification properties + notification.setEventId(UUID.randomUUID().toString()); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + notification.setEventType(ServiceSpecificationCreateNotification.class.getName()); + notification.setResourcePath("/serviceCatalogManagement/v4/serviceSpecification/" + serviceSpecification.getUuid()); + + // Create event + ServiceSpecificationCreateEvent event = new ServiceSpecificationCreateEvent(); + event.setServiceSpecification(serviceSpecification); + + notification.setEvent(event); + return notification; + } + + /** + * Create a service specification delete notification + * @param serviceSpecification The deleted service specification + * @return ServiceSpecificationDeleteNotification + */ + private ServiceSpecificationDeleteNotification createServiceSpecificationDeleteNotification(ServiceSpecification serviceSpecification) { + ServiceSpecificationDeleteNotification notification = new ServiceSpecificationDeleteNotification(); + + // Set common notification properties + notification.setEventId(UUID.randomUUID().toString()); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + notification.setEventType(ServiceSpecificationDeleteNotification.class.getName()); + notification.setResourcePath("/serviceCatalogManagement/v4/serviceSpecification/" + serviceSpecification.getUuid()); + + // Create event + ServiceSpecificationDeleteEvent event = new ServiceSpecificationDeleteEvent(); + event.setServiceSpecification(serviceSpecification); + + notification.setEvent(event); + return notification; + } + + /** + * Create a service specification change notification + * @param serviceSpecification The changed service specification + * @return ServiceSpecificationChangeNotification + */ + private ServiceSpecificationChangeNotification createServiceSpecificationChangeNotification(ServiceSpecification serviceSpecification) { + ServiceSpecificationChangeNotification notification = new ServiceSpecificationChangeNotification(); + + // Set common notification properties + notification.setEventId(UUID.randomUUID().toString()); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + notification.setEventType(ServiceSpecificationChangeNotification.class.getName()); + notification.setResourcePath("/serviceCatalogManagement/v4/serviceSpecification/" + serviceSpecification.getUuid()); + + // Create event + ServiceSpecificationChangeEvent event = new ServiceSpecificationChangeEvent(); + event.setServiceSpecification(serviceSpecification); + + notification.setEvent(event); + return notification; + } +} \ No newline at end of file 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 0bec53ed51fdd1d3edbef018d6d42edcbcc1d72d..e365e0a1af83fedf216ca53b87e73f034fe1c758 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 @@ -134,6 +134,9 @@ public class ServiceSpecificationRepoService { @Autowired ServiceTestSpecificationRepoService serviceTestSpecificationRepoService; + @Autowired + ServiceSpecificationNotificationService serviceSpecificationNotificationService; + private SessionFactory sessionFactory; private static final String METADATADIR = System.getProperty("user.home") + File.separator + ".attachments" @@ -156,6 +159,8 @@ public class ServiceSpecificationRepoService { serviceSpec = this.updateServiceSpecDataFromAPIcall(serviceSpec, serviceServiceSpecification); serviceSpec = this.serviceSpecificationRepo.save(serviceSpec); serviceSpec.fixSpecCharRelationhsipIDs(); + + serviceSpecificationNotificationService.publishServiceSpecificationCreateNotification(serviceSpec); /** * we automatically create s Service Candidate for this spec ready to be @@ -342,7 +347,8 @@ public class ServiceSpecificationRepoService { /** * prior deleting we need to delete other dependency objects */ - + + serviceSpecificationNotificationService.publishServiceSpecificationDeleteNotification(s); this.serviceSpecificationRepo.delete(s); return null; } @@ -381,6 +387,8 @@ public class ServiceSpecificationRepoService { serviceSpec = this.serviceSpecificationRepo.save(serviceSpec); serviceSpec.fixSpecCharRelationhsipIDs(); + serviceSpecificationNotificationService.publishServiceSpecificationChangeNotification(serviceSpec); + //save the equivalent candidate ServiceCandidate serviceCandidateObj = candidateRepoService.findById( serviceSpec.getServiceCandidateObjId() ); if ( serviceCandidateObj!=null) { diff --git a/src/main/resources/application-testing.yml b/src/main/resources/application-testing.yml index 251dbc6c603670f148b00e2a178e3d360fa6d748..cbb0b1fd16e9240a9b37e31e02a3bb2efc7d0da1 100644 --- a/src/main/resources/application-testing.yml +++ b/src/main/resources/application-testing.yml @@ -215,6 +215,14 @@ EVENT_PRODUCT_OFFERING_PRICE_DELETE: "jms:topic:EVENT.PRODUCTOFFERINGPRICE.DELET EVENT_PRODUCT_OFFERING_PRICE_ATTRIBUTE_VALUE_CHANGE: "jms:topic:EVENT.PRODUCTOFFERINGPRICE.ATTRCHANGED" EVENT_PRODUCT_OFFERING_PRICE_STATE_CHANGE: "jms:topic:EVENT.PRODUCTOFFERINGPRICE.STATECHANGED" +EVENT_SERVICE_CATALOG_CREATE: "jms:topic:EVENT.SERVICECATALOG.CREATE" +EVENT_SERVICE_CATALOG_DELETE: "jms:topic:EVENT.SERVICECATALOG.DELETE" +EVENT_SERVICE_CATEGORY_CREATE: "jms:topic:EVENT.SERVICECATEGORY.CREATE" +EVENT_SERVICE_CATEGORY_DELETE: "jms:topic:EVENT.SERVICECATEGORY.DELETE" +EVENT_SERVICE_SPECIFICATION_CREATE: "jms:topic:EVENT.SERVICESPECIFICATION.CREATE" +EVENT_SERVICE_SPECIFICATION_DELETE: "jms:topic:EVENT.SERVICESPECIFICATION.DELETE" +EVENT_SERVICE_SPECIFICATION_CHANGE: "jms:topic:EVENT.SERVICESPECIFICATION.CHANGE" + #QUEUE MESSSAGES WITH VNFNSD CATALOG NFV_CATALOG_GET_NSD_BY_ID: "jms:queue:NFVCATALOG.GET.NSD_BY_ID" diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 2cf3438ac025cecde55ad09c2d732baa953eebcb..30bccc8b745a51fe7485383f68babe11eeaa27ae 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -225,6 +225,14 @@ EVENT_PRODUCT_OFFERING_PRICE_DELETE: "jms:topic:EVENT.PRODUCTOFFERINGPRICE.DELET EVENT_PRODUCT_OFFERING_PRICE_ATTRIBUTE_VALUE_CHANGE: "jms:topic:EVENT.PRODUCTOFFERINGPRICE.ATTRCHANGED" EVENT_PRODUCT_OFFERING_PRICE_STATE_CHANGE: "jms:topic:EVENT.PRODUCTOFFERINGPRICE.STATECHANGED" +EVENT_SERVICE_CATALOG_CREATE: "jms:topic:EVENT.SERVICECATALOG.CREATE" +EVENT_SERVICE_CATALOG_DELETE: "jms:topic:EVENT.SERVICECATALOG.DELETE" +EVENT_SERVICE_CATEGORY_CREATE: "jms:topic:EVENT.SERVICECATEGORY.CREATE" +EVENT_SERVICE_CATEGORY_DELETE: "jms:topic:EVENT.SERVICECATEGORY.DELETE" +EVENT_SERVICE_SPECIFICATION_CREATE: "jms:topic:EVENT.SERVICESPECIFICATION.CREATE" +EVENT_SERVICE_SPECIFICATION_DELETE: "jms:topic:EVENT.SERVICESPECIFICATION.DELETE" +EVENT_SERVICE_SPECIFICATION_CHANGE: "jms:topic:EVENT.SERVICESPECIFICATION.CHANGE" + #QUEUE MESSSAGES WITH VNFNSD CATALOG NFV_CATALOG_GET_NSD_BY_ID: "jms:queue:NFVCATALOG.GET.NSD_BY_ID" diff --git a/src/test/java/org/etsi/osl/services/api/pcm620/CatalogNotificationIntegrationTest.java b/src/test/java/org/etsi/osl/services/api/pcm620/CatalogNotificationIntegrationTest.java index a52faa91f54cb7135147e30c1a9bee15bf5abd39..b0dd117ac8921cbb05b93976d057f574457a29d2 100644 --- a/src/test/java/org/etsi/osl/services/api/pcm620/CatalogNotificationIntegrationTest.java +++ b/src/test/java/org/etsi/osl/services/api/pcm620/CatalogNotificationIntegrationTest.java @@ -1,6 +1,7 @@ package org.etsi.osl.services.api.pcm620; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; @@ -19,6 +20,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; @@ -43,6 +45,9 @@ public class CatalogNotificationIntegrationTest extends BaseIT { private AutoCloseable mocks; + @Value("${EVENT_PRODUCT_CATALOG_CREATE}") + private String EVENT_CATALOG_CREATE = ""; + @BeforeAll public void setupOnce() { mvc = MockMvcBuilders @@ -80,10 +85,10 @@ public class CatalogNotificationIntegrationTest extends BaseIT { // Assert - Verify notification was published to Camel ProducerTemplate (ActiveMQ) verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( - anyString(), // topic name + eq(EVENT_CATALOG_CREATE), // topic name argThat(body -> { // Verify the body contains JSON with catalog create event - return body != null && body.toString().contains("CatalogCreateNotification"); + return body != null && body.toString().contains("A catalog to test notifications"); }), anyMap() // headers ); diff --git a/src/test/java/org/etsi/osl/services/api/scm633/HubApiControllerTest.java b/src/test/java/org/etsi/osl/services/api/scm633/HubApiControllerTest.java index 77dd2c4e72aa94b163e98a5c0bd371eea1f8d7d0..0a64767c2720bfa8a9161b93233104226ba8d098 100644 --- a/src/test/java/org/etsi/osl/services/api/scm633/HubApiControllerTest.java +++ b/src/test/java/org/etsi/osl/services/api/scm633/HubApiControllerTest.java @@ -67,14 +67,14 @@ public class HubApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( eventSubscriptionInput ) )) - .andExpect(status().is(501)); + .andExpect(status().isCreated()); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/hub") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( eventSubscriptionInput ) )) - .andExpect(status().is(501)); + .andExpect(status().isCreated()); } @@ -86,6 +86,6 @@ public class HubApiControllerTest extends BaseIT { .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is(501)); + .andExpect(status().isNotFound()); } } \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/services/api/scm633/ListenerApiControllerTest.java b/src/test/java/org/etsi/osl/services/api/scm633/ListenerApiControllerTest.java index 5e44fefd61a8fefe08f34c881d2f14b3c6440190..a9db253ecc4f93300987d5e5f667c36f82b71a4f 100644 --- a/src/test/java/org/etsi/osl/services/api/scm633/ListenerApiControllerTest.java +++ b/src/test/java/org/etsi/osl/services/api/scm633/ListenerApiControllerTest.java @@ -77,14 +77,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCandidateChangeNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCandidateChangeNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCandidateChangeNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -103,14 +103,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCandidateCreateNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCandidateCreateNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCandidateCreateNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -129,14 +129,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCandidateDeleteNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCandidateDeleteNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCandidateDeleteNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -155,14 +155,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCatalogBatchNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCatalogBatchNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCatalogBatchNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -181,14 +181,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCatalogChangeNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCatalogChangeNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCatalogChangeNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -207,14 +207,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCatalogCreateNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCatalogCreateNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCatalogCreateNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -233,14 +233,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCatalogDeleteNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCatalogDeleteNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCatalogDeleteNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -259,14 +259,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCategoryChangeNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCategoryChangeNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCategoryChangeNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -285,14 +285,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCategoryCreateNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCategoryCreateNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCategoryCreateNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -311,14 +311,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCategoryDeleteNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceCategoryDeleteNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceCategoryDeleteNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -337,14 +337,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceSpecificationChangeNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceSpecificationChangeNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceSpecificationChangeNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -363,14 +363,14 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceSpecificationCreateNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceSpecificationCreateNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceSpecificationCreateNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } @@ -389,13 +389,13 @@ public class ListenerApiControllerTest extends BaseIT { .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceSpecificationDeleteNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); // Test when not providing an "Accept" request header mvc.perform(MockMvcRequestBuilders.post("/serviceCatalogManagement/v4/listener/serviceSpecificationDeleteNotification") .with(SecurityMockMvcRequestPostProcessors.csrf()) .contentType(MediaType.APPLICATION_JSON) .content( JsonUtils.toJson( serviceSpecificationDeleteNotification ) )) - .andExpect(status().is(501)); + .andExpect(status().is(200)); } } \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/services/api/scm633/ServiceCatalogApiRouteBuilderEventsTest.java b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCatalogApiRouteBuilderEventsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..489c07e2a4af1a2eaca1d44023a9eb61b9d6cb6e --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCatalogApiRouteBuilderEventsTest.java @@ -0,0 +1,261 @@ +package org.etsi.osl.services.api.scm633; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.Map; +import org.apache.camel.ProducerTemplate; +import org.aspectj.lang.annotation.Before; +import org.etsi.osl.centrallog.client.CentralLogger; +import org.etsi.osl.services.api.BaseIT; +import org.etsi.osl.tmf.scm633.api.ServiceCatalogApiRouteBuilderEvents; +import org.etsi.osl.tmf.scm633.model.ServiceCatalog; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogDeleteNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryDeleteNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationChangeNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationDeleteNotification; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.test.util.ReflectionTestUtils; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + +public class ServiceCatalogApiRouteBuilderEventsTest extends BaseIT { + + @Mock + private ProducerTemplate template; + + @Mock + private CentralLogger centralLogger; + + @InjectMocks + private ServiceCatalogApiRouteBuilderEvents routeBuilderEvents; + + + private AutoCloseable mocks; + + @BeforeAll + public void setup() { + mocks = MockitoAnnotations.openMocks(this); + + // Set event topic properties using reflection + ReflectionTestUtils.setField(routeBuilderEvents, "EVENT_SERVICE_CATALOG_CREATE", "direct:EVENT_SERVICE_CATALOG_CREATE"); + ReflectionTestUtils.setField(routeBuilderEvents, "EVENT_SERVICE_CATALOG_DELETE", "direct:EVENT_SERVICE_CATALOG_DELETE"); + ReflectionTestUtils.setField(routeBuilderEvents, "EVENT_SERVICE_CATEGORY_CREATE", "direct:EVENT_SERVICE_CATEGORY_CREATE"); + ReflectionTestUtils.setField(routeBuilderEvents, "EVENT_SERVICE_CATEGORY_DELETE", "direct:EVENT_SERVICE_CATEGORY_DELETE"); + ReflectionTestUtils.setField(routeBuilderEvents, "EVENT_SERVICE_SPECIFICATION_CREATE", "direct:EVENT_SERVICE_SPECIFICATION_CREATE"); + ReflectionTestUtils.setField(routeBuilderEvents, "EVENT_SERVICE_SPECIFICATION_DELETE", "direct:EVENT_SERVICE_SPECIFICATION_DELETE"); + ReflectionTestUtils.setField(routeBuilderEvents, "EVENT_SERVICE_SPECIFICATION_CHANGE", "direct:EVENT_SERVICE_SPECIFICATION_CHANGE"); + } + + + @PersistenceContext + private EntityManager entityManager; + + + @AfterEach + public void tearDown() throws Exception { + if (mocks != null) { + mocks.close(); + } + if (entityManager != null) { + entityManager.clear(); + } + } + + @Test + public void testPublishServiceCatalogCreateEvent() { + // Arrange + ServiceCatalog serviceCatalog = new ServiceCatalog(); + serviceCatalog.setUuid("test-catalog-123"); + + ServiceCatalogCreateNotification notification = new ServiceCatalogCreateNotification(); + notification.setEventId("event-123"); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + + // Act + routeBuilderEvents.publishEvent(notification, "test-catalog-123"); + + // Assert + verify(template, times(1)).sendBodyAndHeaders( + eq("direct:EVENT_SERVICE_CATALOG_CREATE"), + any(String.class), + any(Map.class) + ); + } + + @Test + public void testPublishServiceCatalogDeleteEvent() { + // Arrange + ServiceCatalogDeleteNotification notification = new ServiceCatalogDeleteNotification(); + notification.setEventId("event-456"); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + + // Act + routeBuilderEvents.publishEvent(notification, "test-catalog-456"); + + // Assert + verify(template, times(1)).sendBodyAndHeaders( + eq("direct:EVENT_SERVICE_CATALOG_DELETE"), + any(String.class), + any(Map.class) + ); + } + + @Test + public void testPublishServiceCategoryCreateEvent() { + // Arrange + ServiceCategoryCreateNotification notification = new ServiceCategoryCreateNotification(); + notification.setEventId("event-789"); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + + // Act + routeBuilderEvents.publishEvent(notification, "test-category-789"); + + // Assert + verify(template, times(1)).sendBodyAndHeaders( + eq("direct:EVENT_SERVICE_CATEGORY_CREATE"), + any(String.class), + any(Map.class) + ); + } + + @Test + public void testPublishServiceCategoryDeleteEvent() { + // Arrange + ServiceCategoryDeleteNotification notification = new ServiceCategoryDeleteNotification(); + notification.setEventId("event-101112"); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + + // Act + routeBuilderEvents.publishEvent(notification, "test-category-101112"); + + // Assert + verify(template, times(1)).sendBodyAndHeaders( + eq("direct:EVENT_SERVICE_CATEGORY_DELETE"), + any(String.class), + any(Map.class) + ); + } + + @Test + public void testPublishServiceSpecificationCreateEvent() { + // Arrange + ServiceSpecificationCreateNotification notification = new ServiceSpecificationCreateNotification(); + notification.setEventId("event-131415"); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + + // Act + routeBuilderEvents.publishEvent(notification, "test-spec-131415"); + + // Assert + verify(template, times(1)).sendBodyAndHeaders( + eq("direct:EVENT_SERVICE_SPECIFICATION_CREATE"), + any(String.class), + any(Map.class) + ); + } + + @Test + public void testPublishServiceSpecificationDeleteEvent() { + // Arrange + ServiceSpecificationDeleteNotification notification = new ServiceSpecificationDeleteNotification(); + notification.setEventId("event-161718"); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + + // Act + routeBuilderEvents.publishEvent(notification, "test-spec-161718"); + + // Assert + verify(template, times(1)).sendBodyAndHeaders( + eq("direct:EVENT_SERVICE_SPECIFICATION_DELETE"), + any(String.class), + any(Map.class) + ); + } + + @Test + public void testPublishServiceSpecificationChangeEvent() { + // Arrange + ServiceSpecificationChangeNotification notification = new ServiceSpecificationChangeNotification(); + notification.setEventId("event-192021"); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + + // Act + routeBuilderEvents.publishEvent(notification, "test-spec-192021"); + + // Assert + verify(template, times(1)).sendBodyAndHeaders( + eq("direct:EVENT_SERVICE_SPECIFICATION_CHANGE"), + any(String.class), + any(Map.class) + ); + } + + @Test + public void testPublishEventWithNullEventId() { + // Arrange + ServiceCatalogCreateNotification notification = new ServiceCatalogCreateNotification(); + notification.setEventId(null); + notification.setEventTime(OffsetDateTime.now(ZoneOffset.UTC)); + + // Act + routeBuilderEvents.publishEvent(notification, "test-catalog-null"); + + // Assert + verify(template, times(1)).sendBodyAndHeaders( + eq("direct:EVENT_SERVICE_CATALOG_CREATE"), + any(String.class), + any(Map.class) + ); + } + + @Test + public void testPublishEventWithDifferentNotificationTypes() { + // Test that all notification types are handled correctly + + // Service Catalog + ServiceCatalogCreateNotification catalogCreate = new ServiceCatalogCreateNotification(); + catalogCreate.setEventId("catalog-create"); + routeBuilderEvents.publishEvent(catalogCreate, "catalog-id"); + + ServiceCatalogDeleteNotification catalogDelete = new ServiceCatalogDeleteNotification(); + catalogDelete.setEventId("catalog-delete"); + routeBuilderEvents.publishEvent(catalogDelete, "catalog-id"); + + // Service Category + ServiceCategoryCreateNotification categoryCreate = new ServiceCategoryCreateNotification(); + categoryCreate.setEventId("category-create"); + routeBuilderEvents.publishEvent(categoryCreate, "category-id"); + + ServiceCategoryDeleteNotification categoryDelete = new ServiceCategoryDeleteNotification(); + categoryDelete.setEventId("category-delete"); + routeBuilderEvents.publishEvent(categoryDelete, "category-id"); + + // Service Specification + ServiceSpecificationCreateNotification specCreate = new ServiceSpecificationCreateNotification(); + specCreate.setEventId("spec-create"); + routeBuilderEvents.publishEvent(specCreate, "spec-id"); + + ServiceSpecificationDeleteNotification specDelete = new ServiceSpecificationDeleteNotification(); + specDelete.setEventId("spec-delete"); + routeBuilderEvents.publishEvent(specDelete, "spec-id"); + + ServiceSpecificationChangeNotification specChange = new ServiceSpecificationChangeNotification(); + specChange.setEventId("spec-change"); + routeBuilderEvents.publishEvent(specChange, "spec-id"); + + // Assert all events were published + verify(template, times(7)).sendBodyAndHeaders(any(String.class), any(String.class), any(Map.class)); + } +} \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/services/api/scm633/ServiceCatalogCallbackServiceExtendedTest.java b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCatalogCallbackServiceExtendedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c66279bcb2d79114d89090170b4cba21a1a25878 --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCatalogCallbackServiceExtendedTest.java @@ -0,0 +1,286 @@ +package org.etsi.osl.services.api.scm633; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import java.util.Arrays; +import java.util.List; +import org.etsi.osl.services.api.BaseIT; +import org.etsi.osl.tmf.scm633.model.EventSubscription; +import org.etsi.osl.tmf.scm633.model.ServiceCategory; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreateEvent; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryDeleteEvent; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryDeleteNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationChangeEvent; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationChangeNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreateEvent; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationDeleteEvent; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationDeleteNotification; +import org.etsi.osl.tmf.scm633.reposervices.EventSubscriptionRepoService; +import org.etsi.osl.tmf.scm633.reposervices.ServiceCatalogCallbackService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + +public class ServiceCatalogCallbackServiceExtendedTest extends BaseIT { + + @Mock + private EventSubscriptionRepoService eventSubscriptionRepoService; + + @Mock + private RestTemplate restTemplate; + + @InjectMocks + private ServiceCatalogCallbackService serviceCatalogCallbackService; + + + private AutoCloseable mocks; + + @BeforeAll + public void setup() { + mocks = MockitoAnnotations.openMocks(this); + } + + + @PersistenceContext + private EntityManager entityManager; + + + @AfterEach + public void tearDown() throws Exception { + if (mocks != null) { + mocks.close(); + } + if (entityManager != null) { + entityManager.clear(); + } + } + + + + @Test + public void testSendServiceCategoryCreateCallback() { + // Arrange + ServiceCategory serviceCategory = new ServiceCategory(); + serviceCategory.setUuid("test-category-123"); + serviceCategory.setName("Test Category"); + + ServiceCategoryCreateEvent event = new ServiceCategoryCreateEvent(); + event.setServiceCategory(serviceCategory); + + EventSubscription subscription1 = new EventSubscription(); + subscription1.setId("sub-1"); + subscription1.setCallback("http://localhost:8080/callback"); + + EventSubscription subscription2 = new EventSubscription(); + subscription2.setId("sub-2"); + subscription2.setCallback("http://localhost:8081/callback"); + subscription2.setQuery("servicecategory"); + + List subscriptions = Arrays.asList(subscription1, subscription2); + + when(eventSubscriptionRepoService.findAll()).thenReturn(subscriptions); + when(restTemplate.exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + ServiceCategoryCreateNotification notif = new ServiceCategoryCreateNotification(); + notif.setEvent(event); + // Act + serviceCatalogCallbackService.sendServiceCategoryCreateCallback(notif ); + + // Assert + verify(restTemplate, times(2)).exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); + } + + @Test + public void testSendServiceCategoryDeleteCallback() { + // Arrange + ServiceCategory serviceCategory = new ServiceCategory(); + serviceCategory.setUuid("test-category-456"); + serviceCategory.setName("Test Category to Delete"); + + ServiceCategoryDeleteEvent event = new ServiceCategoryDeleteEvent(); + event.setServiceCategory(serviceCategory); + + EventSubscription subscription = new EventSubscription(); + subscription.setId("sub-1"); + subscription.setCallback("http://localhost:8080/callback"); + subscription.setQuery("servicecategory.delete"); + + List subscriptions = Arrays.asList(subscription); + + when(eventSubscriptionRepoService.findAll()).thenReturn(subscriptions); + when(restTemplate.exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + + ServiceCategoryDeleteNotification notif = new ServiceCategoryDeleteNotification(); + notif.setEvent(event); + // Act + serviceCatalogCallbackService.sendServiceCategoryDeleteCallback(notif); + + // Assert + verify(restTemplate, times(1)).exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); + } + + @Test + public void testSendServiceSpecificationCreateCallback() { + // Arrange + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setUuid("test-spec-123"); + serviceSpecification.setName("Test Specification"); + + ServiceSpecificationCreateEvent event = new ServiceSpecificationCreateEvent(); + event.setServiceSpecification(serviceSpecification); + + EventSubscription subscription = new EventSubscription(); + subscription.setId("sub-1"); + subscription.setCallback("http://localhost:8080/callback"); + subscription.setQuery("servicespecification.create"); + + List subscriptions = Arrays.asList(subscription); + + when(eventSubscriptionRepoService.findAll()).thenReturn(subscriptions); + when(restTemplate.exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + // Act + + ServiceSpecificationCreateNotification notif = new ServiceSpecificationCreateNotification(); + notif.setEvent(event); + serviceCatalogCallbackService.sendServiceSpecificationCreateCallback(notif); + + // Assert + verify(restTemplate, times(1)).exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); + } + + @Test + public void testSendServiceSpecificationDeleteCallback() { + // Arrange + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setUuid("test-spec-456"); + serviceSpecification.setName("Test Specification to Delete"); + + ServiceSpecificationDeleteEvent event = new ServiceSpecificationDeleteEvent(); + event.setServiceSpecification(serviceSpecification); + + EventSubscription subscription = new EventSubscription(); + subscription.setId("sub-1"); + subscription.setCallback("http://localhost:8080/callback"); + + List subscriptions = Arrays.asList(subscription); + + when(eventSubscriptionRepoService.findAll()).thenReturn(subscriptions); + when(restTemplate.exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + // Act + ServiceSpecificationDeleteNotification notif = new ServiceSpecificationDeleteNotification(); + notif.setEvent(event); + serviceCatalogCallbackService.sendServiceSpecificationDeleteCallback(notif); + + // Assert + verify(restTemplate, times(1)).exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); + } + + @Test + public void testSendServiceSpecificationChangeCallback() { + // Arrange + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setUuid("test-spec-789"); + serviceSpecification.setName("Test Specification to Change"); + + ServiceSpecificationChangeEvent event = new ServiceSpecificationChangeEvent(); + event.setServiceSpecification(serviceSpecification); + + EventSubscription subscription = new EventSubscription(); + subscription.setId("sub-1"); + subscription.setCallback("http://localhost:8080/callback"); + subscription.setQuery("servicespecification.change"); + + List subscriptions = Arrays.asList(subscription); + + when(eventSubscriptionRepoService.findAll()).thenReturn(subscriptions); + when(restTemplate.exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + // Act + ServiceSpecificationChangeNotification notif = new ServiceSpecificationChangeNotification(); + notif.setEvent(event); + serviceCatalogCallbackService.sendServiceSpecificationChangeCallback(notif); + + // Assert + verify(restTemplate, times(1)).exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); + } + + @Test + public void testShouldNotifySubscriptionWithNoQuery() { + // Test that subscriptions with no query receive all events + EventSubscription subscription = new EventSubscription(); + subscription.setId("sub-1"); + subscription.setCallback("http://localhost:8080/callback"); + // No query set + + ServiceCategoryCreateEvent event = new ServiceCategoryCreateEvent(); + ServiceCategory serviceCategory = new ServiceCategory(); + serviceCategory.setName("Test"); + event.setServiceCategory(serviceCategory); + + List subscriptions = Arrays.asList(subscription); + + when(eventSubscriptionRepoService.findAll()).thenReturn(subscriptions); + when(restTemplate.exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + // Act + ServiceCategoryCreateNotification notif = new ServiceCategoryCreateNotification(); + notif.setEvent(event); + serviceCatalogCallbackService.sendServiceCategoryCreateCallback(notif); + + // Assert - should call callback even with no query + verify(restTemplate, times(1)).exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); + } + + @Test + public void testShouldNotifySubscriptionWithMatchingQuery() { + // Test specific query matching + EventSubscription subscription = new EventSubscription(); + subscription.setId("sub-1"); + subscription.setCallback("http://localhost:8080/callback"); + subscription.setQuery("servicespecification"); + + ServiceSpecificationCreateEvent event = new ServiceSpecificationCreateEvent(); + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setName("Test"); + event.setServiceSpecification(serviceSpecification); + + List subscriptions = Arrays.asList(subscription); + + when(eventSubscriptionRepoService.findAll()).thenReturn(subscriptions); + when(restTemplate.exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + // Act + ServiceSpecificationCreateNotification notif = new ServiceSpecificationCreateNotification(); + notif.setEvent(event); + serviceCatalogCallbackService.sendServiceSpecificationCreateCallback(notif); + + // Assert + verify(restTemplate, times(1)).exchange(any(String.class), eq(HttpMethod.POST), any(HttpEntity.class), eq(String.class)); + } +} \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/services/api/scm633/ServiceCatalogManagementNotificationEndToEndTest.java b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCatalogManagementNotificationEndToEndTest.java new file mode 100644 index 0000000000000000000000000000000000000000..262b54858e6959b9fca205cee8f5c7952d86ac4f --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCatalogManagementNotificationEndToEndTest.java @@ -0,0 +1,298 @@ +package org.etsi.osl.services.api.scm633; + +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import java.util.Arrays; +import java.util.List; +import org.apache.camel.ProducerTemplate; +import org.etsi.osl.services.api.BaseIT; +import org.etsi.osl.tmf.scm633.model.EventSubscription; +import org.etsi.osl.tmf.scm633.model.ServiceCatalog; +import org.etsi.osl.tmf.scm633.model.ServiceCatalogCreate; +import org.etsi.osl.tmf.scm633.model.ServiceCategory; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreate; +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.EventSubscriptionRepoService; +import org.etsi.osl.tmf.scm633.reposervices.ServiceSpecificationRepoService; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.context.WebApplicationContext; + + +public class ServiceCatalogManagementNotificationEndToEndTest extends BaseIT{ + + @Autowired + private MockMvc mvc; + + @Autowired + private WebApplicationContext context; + + @Autowired + private CatalogRepoService catalogRepoService; + + @Autowired + private CategoryRepoService categoryRepoService; + + @Autowired + private ServiceSpecificationRepoService serviceSpecificationRepoService; + + @MockBean + @Qualifier("scm633EventSubscriptionRepoService") + private EventSubscriptionRepoService eventSubscriptionRepoService; + + @MockBean + private ProducerTemplate producerTemplate; + + @MockBean + private RestTemplate restTemplate; + + private AutoCloseable mocks; + + @BeforeAll + public void setup() { + mocks = MockitoAnnotations.openMocks(this); + mvc = MockMvcBuilders + .webAppContextSetup(context) + .apply(springSecurity()) + .build(); + + // Reset all mocks to clear state between tests + reset(producerTemplate); + reset(restTemplate); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testCompleteServiceCatalogManagementNotificationFlow() { + // Setup event subscription for testing callbacks + EventSubscription subscription = new EventSubscription(); + subscription.setCallback("http://localhost:8080/test-callback"); + subscription.setQuery("servicecatalog"); + + when(eventSubscriptionRepoService.findAll()).thenReturn(Arrays.asList(subscription)); + when(restTemplate.exchange(anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + // Test Service Catalog lifecycle + ServiceCatalogCreate catalogCreate = new ServiceCatalogCreate(); + catalogCreate.setName("End-to-End Test Catalog"); + catalogCreate.setDescription("A catalog for end-to-end testing"); + + ServiceCatalog createdCatalog = catalogRepoService.addCatalog(catalogCreate); + + // Verify catalog create notification was published to Camel + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCatalogCreateNotification")), + anyMap() + ); + + // Delete catalog + catalogRepoService.deleteById(createdCatalog.getUuid()); + + // Verify catalog delete notification was published to Camel + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCatalogDeleteNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testCompleteServiceCategoryNotificationFlow() { + // Setup event subscription for testing callbacks + EventSubscription subscription = new EventSubscription(); + subscription.setCallback("http://localhost:8080/test-callback"); + subscription.setQuery("servicecategory"); + + when(eventSubscriptionRepoService.findAll()).thenReturn(Arrays.asList(subscription)); + when(restTemplate.exchange(anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + // Test Service Category lifecycle + ServiceCategoryCreate categoryCreate = new ServiceCategoryCreate(); + categoryCreate.setName("End-to-End Test Category"); + categoryCreate.setDescription("A category for end-to-end testing"); + + ServiceCategory createdCategory = categoryRepoService.addCategory(categoryCreate); + + // Verify category create notification was published to Camel + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCategoryCreateNotification")), + anyMap() + ); + + // Delete category + categoryRepoService.deleteById(createdCategory.getUuid()); + + // Verify category delete notification was published to Camel + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCategoryDeleteNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testCompleteServiceSpecificationNotificationFlow() { + // Setup event subscription for testing callbacks + EventSubscription subscription = new EventSubscription(); + subscription.setCallback("http://localhost:8080/test-callback"); + subscription.setQuery("servicespecification"); + + when(eventSubscriptionRepoService.findAll()).thenReturn(Arrays.asList(subscription)); + when(restTemplate.exchange(anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + // Test Service Specification lifecycle + ServiceSpecificationCreate specCreate = new ServiceSpecificationCreate(); + specCreate.setName("End-to-End Test Specification"); + specCreate.setDescription("A specification for end-to-end testing"); + + ServiceSpecification createdSpec = serviceSpecificationRepoService.addServiceSpecification(specCreate); + + // Verify specification create notification was published to Camel + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationCreateNotification")), + anyMap() + ); + + // Update specification + ServiceSpecificationUpdate specUpdate = new ServiceSpecificationUpdate(); + specUpdate.setDescription("Updated description for end-to-end testing"); + + ServiceSpecification updatedSpec = serviceSpecificationRepoService.updateServiceSpecification(createdSpec.getUuid(), specUpdate); + + // Verify specification change notification was published to Camel + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationChangeNotification")), + anyMap() + ); + + // Delete specification + serviceSpecificationRepoService.deleteByUuid(createdSpec.getUuid()); + + // Verify specification delete notification was published to Camel + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationDeleteNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testMultipleSubscriptionsWithDifferentQueries() { + // Setup multiple event subscriptions with different query filters + EventSubscription allEventsSubscription = new EventSubscription(); + allEventsSubscription.setCallback("http://localhost:8080/all-events"); + // No query - should receive all events + + EventSubscription catalogOnlySubscription = new EventSubscription(); + catalogOnlySubscription.setCallback("http://localhost:8080/catalog-only"); + catalogOnlySubscription.setQuery("servicecatalog"); + + EventSubscription categoryOnlySubscription = new EventSubscription(); + categoryOnlySubscription.setCallback("http://localhost:8080/category-only"); + categoryOnlySubscription.setQuery("servicecategory"); + + EventSubscription specOnlySubscription = new EventSubscription(); + specOnlySubscription.setCallback("http://localhost:8080/spec-only"); + specOnlySubscription.setQuery("servicespecification"); + + List subscriptions = Arrays.asList( + allEventsSubscription, catalogOnlySubscription, categoryOnlySubscription, specOnlySubscription + ); + + when(eventSubscriptionRepoService.findAll()).thenReturn(subscriptions); + when(restTemplate.exchange(anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), eq(String.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + + // Create entities to trigger notifications + ServiceCatalogCreate catalogCreate = new ServiceCatalogCreate(); + catalogCreate.setName("Multi-Subscription Test Catalog"); + ServiceCatalog catalog = catalogRepoService.addCatalog(catalogCreate); + + ServiceCategoryCreate categoryCreate = new ServiceCategoryCreate(); + categoryCreate.setName("Multi-Subscription Test Category"); + ServiceCategory category = categoryRepoService.addCategory(categoryCreate); + + ServiceSpecificationCreate specCreate = new ServiceSpecificationCreate(); + specCreate.setName("Multi-Subscription Test Specification"); + ServiceSpecification spec = serviceSpecificationRepoService.addServiceSpecification(specCreate); + + // Verify notifications were published to Camel for all three entity types + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCatalogCreateNotification")), + anyMap() + ); + + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCategoryCreateNotification")), + anyMap() + ); + + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationCreateNotification")), + anyMap() + ); + + // Verify multiple HTTP calls are made for different subscriptions + verify(restTemplate, timeout(5000).atLeast(3)) + .exchange(anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), eq(String.class)); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testNotificationSystemWithInvalidCallback() { + // Setup event subscription with invalid callback URL + EventSubscription subscription = new EventSubscription(); + subscription.setCallback("http://invalid-callback-url:9999/callback"); + + when(eventSubscriptionRepoService.findAll()).thenReturn(Arrays.asList(subscription)); + when(restTemplate.exchange(anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any(), eq(String.class))) + .thenThrow(new RuntimeException("Connection refused")); + + // Create entity to trigger notification + ServiceCatalogCreate catalogCreate = new ServiceCatalogCreate(); + catalogCreate.setName("Invalid Callback Test Catalog"); + ServiceCatalog catalog = catalogRepoService.addCatalog(catalogCreate); + + // Verify notification was still published to Camel even with callback failure + verify(producerTemplate, timeout(5000)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCatalogCreateNotification")), + anyMap() + ); + } +} diff --git a/src/test/java/org/etsi/osl/services/api/scm633/ServiceCategoryNotificationIntegrationTest.java b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCategoryNotificationIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..524258e85488c0d9a20c907504a8ca9e67f753b9 --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCategoryNotificationIntegrationTest.java @@ -0,0 +1,175 @@ +package org.etsi.osl.services.api.scm633; + +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import org.apache.camel.ProducerTemplate; +import org.etsi.osl.services.api.BaseIT; +import org.etsi.osl.tmf.scm633.model.ServiceCategory; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreate; +import org.etsi.osl.tmf.scm633.reposervices.CategoryRepoService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + + +public class ServiceCategoryNotificationIntegrationTest extends BaseIT{ + + @Autowired + private MockMvc mvc; + + @Autowired + private WebApplicationContext context; + + @Autowired + private CategoryRepoService categoryRepoService; + + @MockBean + private ProducerTemplate producerTemplate; + + private AutoCloseable mocks; + + @BeforeAll + public void setup() { + mocks = MockitoAnnotations.openMocks(this); + mvc = MockMvcBuilders + .webAppContextSetup(context) + .apply(springSecurity()) + .build(); + } + + @PersistenceContext + private EntityManager entityManager; + + + @AfterEach + public void tearDown() throws Exception { + if (mocks != null) { + mocks.close(); + } + if (entityManager != null) { + entityManager.clear(); + } + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testServiceCategoryCreateNotificationTriggered() { + // Arrange + ServiceCategoryCreate serviceCategoryCreate = new ServiceCategoryCreate(); + serviceCategoryCreate.setName("Test Integration Category"); + serviceCategoryCreate.setDescription("A test service category for integration testing"); + + // Act + ServiceCategory createdCategory = categoryRepoService.addCategory(serviceCategoryCreate); + + // Assert - Verify notification was published to Camel + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCategoryCreateNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testServiceCategoryDeleteNotificationTriggered() { + // Arrange - First create a category + ServiceCategoryCreate serviceCategoryCreate = new ServiceCategoryCreate(); + serviceCategoryCreate.setName("Test Category for Deletion"); + serviceCategoryCreate.setDescription("A test service category to be deleted"); + + ServiceCategory createdCategory = categoryRepoService.addCategory(serviceCategoryCreate); + String categoryId = createdCategory.getUuid(); + + // Act - Delete the category + boolean deleted = categoryRepoService.deleteById(categoryId); + + // Assert - Verify delete notification was published to Camel + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCategoryDeleteNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testServiceCategoryAddWithDirectObjectNotificationTriggered() { + // Arrange + ServiceCategory serviceCategory = new ServiceCategory(); + serviceCategory.setName("Test Direct Category"); + serviceCategory.setDescription("A test service category added directly"); + + // Act + ServiceCategory createdCategory = categoryRepoService.addCategory(serviceCategory); + + // Assert - Verify notification was published to Camel + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCategoryCreateNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testServiceCategoryDeleteWithNonExistentId() { + // Act + boolean deleted = categoryRepoService.deleteById("non-existent-id"); + + // Assert - No notification should be triggered for non-existent categories + verify(producerTemplate, timeout(2000).times(0)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceCategoryDeleteNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testMultipleServiceCategoryOperationsNotifications() { + // Test multiple operations to ensure notifications are properly triggered + + // Create first category + ServiceCategoryCreate category1 = new ServiceCategoryCreate(); + category1.setName("Test Category 1"); + category1.setDescription("First test category"); + ServiceCategory created1 = categoryRepoService.addCategory(category1); + + // Create second category + ServiceCategoryCreate category2 = new ServiceCategoryCreate(); + category2.setName("Test Category 2"); + category2.setDescription("Second test category"); + ServiceCategory created2 = categoryRepoService.addCategory(category2); + + // Delete first category + boolean deleted1 = categoryRepoService.deleteById(created1.getUuid()); + + // Assert multiple notifications were published to Camel + verify(producerTemplate, timeout(5000).times(2)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("First test category")), + anyMap() + ); + + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("Second test category")), + anyMap() + ); + } +} diff --git a/src/test/java/org/etsi/osl/services/api/scm633/ServiceCategoryNotificationServiceTest.java b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCategoryNotificationServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cffecde78456da91117ac83188f48fb35b54ede6 --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/scm633/ServiceCategoryNotificationServiceTest.java @@ -0,0 +1,118 @@ +package org.etsi.osl.services.api.scm633; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import org.etsi.osl.services.api.BaseIT; +import org.etsi.osl.tmf.scm633.api.ServiceCatalogApiRouteBuilderEvents; +import org.etsi.osl.tmf.scm633.model.ServiceCategory; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceCategoryDeleteNotification; +import org.etsi.osl.tmf.scm633.reposervices.ServiceCatalogCallbackService; +import org.etsi.osl.tmf.scm633.reposervices.ServiceCategoryNotificationService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + + +public class ServiceCategoryNotificationServiceTest extends BaseIT{ + + @Mock + private ServiceCatalogApiRouteBuilderEvents eventPublisher; + + @Mock + private ServiceCatalogCallbackService serviceCatalogCallbackService; + + @InjectMocks + private ServiceCategoryNotificationService serviceCategoryNotificationService; + + private AutoCloseable mocks; + + @BeforeAll + public void setup() { + mocks = MockitoAnnotations.openMocks(this); + } + + + @PersistenceContext + private EntityManager entityManager; + + + @AfterEach + public void tearDown() throws Exception { + if (mocks != null) { + mocks.close(); + } + if (entityManager != null) { + entityManager.clear(); + } + } + + @Test + public void testPublishServiceCategoryCreateNotification() { + // Arrange + ServiceCategory serviceCategory = new ServiceCategory(); + serviceCategory.setUuid("test-category-123"); + serviceCategory.setName("Test Service Category"); + serviceCategory.setDescription("A test service category for notifications"); + + // Act + serviceCategoryNotificationService.publishServiceCategoryCreateNotification(serviceCategory); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceCategoryCreateNotification.class), eq("test-category-123")); + verify(serviceCatalogCallbackService, times(1)).sendServiceCategoryCreateCallback(any()); + } + + @Test + public void testPublishServiceCategoryDeleteNotification() { + // Arrange + ServiceCategory serviceCategory = new ServiceCategory(); + serviceCategory.setUuid("test-category-456"); + serviceCategory.setName("Test Service Category to Delete"); + serviceCategory.setDescription("A test service category for deletion notifications"); + + // Act + serviceCategoryNotificationService.publishServiceCategoryDeleteNotification(serviceCategory); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceCategoryDeleteNotification.class), eq("test-category-456")); + verify(serviceCatalogCallbackService, times(1)).sendServiceCategoryDeleteCallback(any()); + } + + @Test + public void testPublishServiceCategoryCreateNotificationWithNullUuid() { + // Arrange + ServiceCategory serviceCategory = new ServiceCategory(); + serviceCategory.setName("Test Service Category with Null UUID"); + serviceCategory.setDescription("A test service category with null UUID"); + + // Act + serviceCategoryNotificationService.publishServiceCategoryCreateNotification(serviceCategory); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceCategoryCreateNotification.class), eq(null)); + verify(serviceCatalogCallbackService, times(1)).sendServiceCategoryCreateCallback(any()); + } + + @Test + public void testPublishServiceCategoryDeleteNotificationWithNullUuid() { + // Arrange + ServiceCategory serviceCategory = new ServiceCategory(); + serviceCategory.setName("Test Service Category with Null UUID"); + serviceCategory.setDescription("A test service category with null UUID"); + + // Act + serviceCategoryNotificationService.publishServiceCategoryDeleteNotification(serviceCategory); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceCategoryDeleteNotification.class), eq(null)); + verify(serviceCatalogCallbackService, times(1)).sendServiceCategoryDeleteCallback(any()); + } +} \ No newline at end of file diff --git a/src/test/java/org/etsi/osl/services/api/scm633/ServiceSpecificationNotificationIntegrationTest.java b/src/test/java/org/etsi/osl/services/api/scm633/ServiceSpecificationNotificationIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..02fb7f11ebc012b415180293becca3ac1d31c127 --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/scm633/ServiceSpecificationNotificationIntegrationTest.java @@ -0,0 +1,246 @@ +package org.etsi.osl.services.api.scm633; + +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import org.apache.camel.ProducerTemplate; +import org.etsi.osl.services.api.BaseIT; +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.ServiceSpecificationRepoService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + + +public class ServiceSpecificationNotificationIntegrationTest extends BaseIT{ + + @Autowired + private MockMvc mvc; + + @Autowired + private WebApplicationContext context; + + @Autowired + private ServiceSpecificationRepoService serviceSpecificationRepoService; + + @MockBean + private ProducerTemplate producerTemplate; + + private AutoCloseable mocks; + + @BeforeAll + public void setup() { + mocks = MockitoAnnotations.openMocks(this); + mvc = MockMvcBuilders + .webAppContextSetup(context) + .apply(springSecurity()) + .build(); + } + + + @PersistenceContext + private EntityManager entityManager; + + + @AfterEach + public void tearDown() throws Exception { + if (mocks != null) { + mocks.close(); + } + if (entityManager != null) { + entityManager.clear(); + } + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testServiceSpecificationCreateNotificationTriggered() { + // Arrange + ServiceSpecificationCreate serviceSpecificationCreate = new ServiceSpecificationCreate(); + serviceSpecificationCreate.setName("Test Integration Specification"); + serviceSpecificationCreate.setDescription("A test service specification for integration testing"); + + // Act + ServiceSpecification createdSpec = serviceSpecificationRepoService.addServiceSpecification(serviceSpecificationCreate); + + // Assert - Verify notification was published to Camel + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationCreateNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testServiceSpecificationUpdateNotificationTriggered() { + // Arrange - First create a specification + ServiceSpecificationCreate serviceSpecificationCreate = new ServiceSpecificationCreate(); + serviceSpecificationCreate.setName("Test Specification for Update"); + serviceSpecificationCreate.setDescription("A test service specification to be updated"); + + ServiceSpecification createdSpec = serviceSpecificationRepoService.addServiceSpecification(serviceSpecificationCreate); + String specId = createdSpec.getUuid(); + + // Act - Update the specification + ServiceSpecificationUpdate serviceSpecificationUpdate = new ServiceSpecificationUpdate(); + serviceSpecificationUpdate.setDescription("Updated description"); + + ServiceSpecification updatedSpec = serviceSpecificationRepoService.updateServiceSpecification(specId, serviceSpecificationUpdate); + + // Assert - Verify both create and change notifications were published to Camel + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationCreateNotification")), + anyMap() + ); + + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationChangeNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testServiceSpecificationDeleteNotificationTriggered() { + // Arrange - First create a specification + ServiceSpecificationCreate serviceSpecificationCreate = new ServiceSpecificationCreate(); + serviceSpecificationCreate.setName("Test Specification for Deletion"); + serviceSpecificationCreate.setDescription("A test service specification to be deleted"); + + ServiceSpecification createdSpec = serviceSpecificationRepoService.addServiceSpecification(serviceSpecificationCreate); + String specId = createdSpec.getUuid(); + + // Act - Delete the specification + serviceSpecificationRepoService.deleteByUuid(specId); + + // Assert - Verify delete notification was published to Camel + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationDeleteNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testServiceSpecificationUpdateWithNullSpecification() { + // Act - Try to update a non-existent specification + ServiceSpecificationUpdate serviceSpecificationUpdate = new ServiceSpecificationUpdate(); + serviceSpecificationUpdate.setDescription("Updated description"); + + ServiceSpecification result = serviceSpecificationRepoService.updateServiceSpecification("non-existent-id", serviceSpecificationUpdate); + + // Assert - No notification should be triggered for non-existent specifications + verify(producerTemplate, timeout(2000).times(0)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationChangeNotification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testMultipleServiceSpecificationOperationsNotifications() { + // Test multiple operations to ensure notifications are properly triggered + + // Create first specification + ServiceSpecificationCreate spec1 = new ServiceSpecificationCreate(); + spec1.setName("Test Specification 1"); + spec1.setDescription("First test specification"); + ServiceSpecification created1 = serviceSpecificationRepoService.addServiceSpecification(spec1); + + // Create second specification + ServiceSpecificationCreate spec2 = new ServiceSpecificationCreate(); + spec2.setName("Test Specification 2"); + spec2.setDescription("Second test specification"); + ServiceSpecification created2 = serviceSpecificationRepoService.addServiceSpecification(spec2); + + // Update first specification + ServiceSpecificationUpdate spec1Update = new ServiceSpecificationUpdate(); + spec1Update.setDescription("Updated first specification"); + ServiceSpecification updated1 = serviceSpecificationRepoService.updateServiceSpecification(created1.getUuid(), spec1Update); + + // Delete second specification + serviceSpecificationRepoService.deleteByUuid(created2.getUuid()); + + // Assert multiple notifications were published to Camel + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("First test specification")), + anyMap() + ); + + verify(producerTemplate, timeout(5000).times(2)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("Second test specification")), + anyMap() + ); + + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("Updated first specification")), + anyMap() + ); + } + + @Test + @WithMockUser(username = "osadmin", roles = {"ADMIN"}) + public void testServiceSpecificationLifecycleNotifications() { + // Test complete lifecycle: Create -> Update -> Delete + + // Create + ServiceSpecificationCreate serviceSpecificationCreate = new ServiceSpecificationCreate(); + serviceSpecificationCreate.setName("Lifecycle Test Specification"); + serviceSpecificationCreate.setDescription("A specification for lifecycle testing"); + + ServiceSpecification createdSpec = serviceSpecificationRepoService.addServiceSpecification(serviceSpecificationCreate); + String specId = createdSpec.getUuid(); + + // Update + ServiceSpecificationUpdate serviceSpecificationUpdate = new ServiceSpecificationUpdate(); + serviceSpecificationUpdate.setName("Updated Lifecycle Test Specification"); + serviceSpecificationUpdate.setDescription("Updated description for lifecycle testing"); + + ServiceSpecification updatedSpec = serviceSpecificationRepoService.updateServiceSpecification(specId, serviceSpecificationUpdate); + + // Delete + serviceSpecificationRepoService.deleteByUuid(specId); + + // Assert complete lifecycle notifications were published to Camel + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationCreateNotification")), + anyMap() + ); + + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationChangeNotification")), + anyMap() + ); + + verify(producerTemplate, timeout(5000).times(1)).sendBodyAndHeaders( + anyString(), + argThat(body -> body != null && body.toString().contains("ServiceSpecificationDeleteNotification")), + anyMap() + ); + } +} diff --git a/src/test/java/org/etsi/osl/services/api/scm633/ServiceSpecificationNotificationServiceTest.java b/src/test/java/org/etsi/osl/services/api/scm633/ServiceSpecificationNotificationServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..75a31836eac6141226b9bc63b11281bf5752c4b6 --- /dev/null +++ b/src/test/java/org/etsi/osl/services/api/scm633/ServiceSpecificationNotificationServiceTest.java @@ -0,0 +1,150 @@ +package org.etsi.osl.services.api.scm633; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import org.etsi.osl.services.api.BaseIT; +import org.etsi.osl.tmf.scm633.api.ServiceCatalogApiRouteBuilderEvents; +import org.etsi.osl.tmf.scm633.model.ServiceSpecification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationChangeNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationCreateNotification; +import org.etsi.osl.tmf.scm633.model.ServiceSpecificationDeleteNotification; +import org.etsi.osl.tmf.scm633.reposervices.ServiceCatalogCallbackService; +import org.etsi.osl.tmf.scm633.reposervices.ServiceSpecificationNotificationService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + + +public class ServiceSpecificationNotificationServiceTest extends BaseIT{ + + @Mock + private ServiceCatalogApiRouteBuilderEvents eventPublisher; + + @Mock + private ServiceCatalogCallbackService serviceCatalogCallbackService; + + @InjectMocks + private ServiceSpecificationNotificationService serviceSpecificationNotificationService; + + private AutoCloseable mocks; + + @BeforeAll + public void setup() { + mocks = MockitoAnnotations.openMocks(this); + } + + + @PersistenceContext + private EntityManager entityManager; + + + @AfterEach + public void tearDown() throws Exception { + if (mocks != null) { + mocks.close(); + } + if (entityManager != null) { + entityManager.clear(); + } + } + + @Test + public void testPublishServiceSpecificationCreateNotification() { + // Arrange + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setUuid("test-spec-123"); + serviceSpecification.setName("Test Service Specification"); + serviceSpecification.setDescription("A test service specification for notifications"); + + // Act + serviceSpecificationNotificationService.publishServiceSpecificationCreateNotification(serviceSpecification); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceSpecificationCreateNotification.class), eq("test-spec-123")); + verify(serviceCatalogCallbackService, times(1)).sendServiceSpecificationCreateCallback(any()); + } + + @Test + public void testPublishServiceSpecificationDeleteNotification() { + // Arrange + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setUuid("test-spec-456"); + serviceSpecification.setName("Test Service Specification to Delete"); + serviceSpecification.setDescription("A test service specification for deletion notifications"); + + // Act + serviceSpecificationNotificationService.publishServiceSpecificationDeleteNotification(serviceSpecification); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceSpecificationDeleteNotification.class), eq("test-spec-456")); + verify(serviceCatalogCallbackService, times(1)).sendServiceSpecificationDeleteCallback(any()); + } + + @Test + public void testPublishServiceSpecificationChangeNotification() { + // Arrange + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setUuid("test-spec-789"); + serviceSpecification.setName("Test Service Specification to Change"); + serviceSpecification.setDescription("A test service specification for change notifications"); + + // Act + serviceSpecificationNotificationService.publishServiceSpecificationChangeNotification(serviceSpecification); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceSpecificationChangeNotification.class), eq("test-spec-789")); + verify(serviceCatalogCallbackService, times(1)).sendServiceSpecificationChangeCallback(any()); + } + + @Test + public void testPublishServiceSpecificationCreateNotificationWithNullUuid() { + // Arrange + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setName("Test Service Specification with Null UUID"); + serviceSpecification.setDescription("A test service specification with null UUID"); + + // Act + serviceSpecificationNotificationService.publishServiceSpecificationCreateNotification(serviceSpecification); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceSpecificationCreateNotification.class), eq(null)); + verify(serviceCatalogCallbackService, times(1)).sendServiceSpecificationCreateCallback(any()); + } + + @Test + public void testPublishServiceSpecificationDeleteNotificationWithNullUuid() { + // Arrange + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setName("Test Service Specification with Null UUID"); + serviceSpecification.setDescription("A test service specification with null UUID"); + + // Act + serviceSpecificationNotificationService.publishServiceSpecificationDeleteNotification(serviceSpecification); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceSpecificationDeleteNotification.class), eq(null)); + verify(serviceCatalogCallbackService, times(1)).sendServiceSpecificationDeleteCallback(any()); + } + + @Test + public void testPublishServiceSpecificationChangeNotificationWithNullUuid() { + // Arrange + ServiceSpecification serviceSpecification = new ServiceSpecification(); + serviceSpecification.setName("Test Service Specification with Null UUID"); + serviceSpecification.setDescription("A test service specification with null UUID"); + + // Act + serviceSpecificationNotificationService.publishServiceSpecificationChangeNotification(serviceSpecification); + + // Assert + verify(eventPublisher, times(1)).publishEvent(any(ServiceSpecificationChangeNotification.class), eq(null)); + verify(serviceCatalogCallbackService, times(1)).sendServiceSpecificationChangeCallback(any()); + } +} \ No newline at end of file diff --git a/src/test/resources/testEventSubscriptionInput.json b/src/test/resources/testEventSubscriptionInput.json index bccdb0cdb7f50e92a7ac57abcd18cbe28d5be28e..e55a460129906dcc77e521303b7f01a6b563926a 100644 --- a/src/test/resources/testEventSubscriptionInput.json +++ b/src/test/resources/testEventSubscriptionInput.json @@ -1,3 +1,4 @@ { + "callback": "http://localhost:8080/callback", "query": "test" } \ No newline at end of file