From 5146005daaa14d2929cb66823047f8d868af5588 Mon Sep 17 00:00:00 2001 From: Ashirwada Date: Thu, 31 Oct 2024 16:26:16 +0530 Subject: [PATCH 1/3] Adding event notification endpoint implementation --- .../pom.xml | 169 ++++++++++ .../endpoint/api/EventCreationEndpoint.java | 152 +++++++++ .../endpoint/api/EventPollingEndpoint.java | 194 ++++++++++++ .../api/EventSubscriptionEndpoint.java | 288 ++++++++++++++++++ .../EventNotificationEndPointConstants.java | 36 +++ .../endpoint/util/EventNotificationUtils.java | 115 +++++++ .../endpoint/util/EventSubscriptionUtils.java | 75 +++++ .../src/main/resources/findbugs-exclude.xml | 21 ++ .../src/main/resources/findbugs-include.xml | 22 ++ .../webapp/META-INF/webapp-classloading.xml | 35 +++ .../src/main/webapp/WEB-INF/beans.xml | 36 +++ .../src/main/webapp/WEB-INF/web.xml | 71 +++++ financial-services-accelerator/pom.xml | 1 + pom.xml | 19 +- 14 files changed, 1232 insertions(+), 2 deletions(-) create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/pom.xml create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventCreationEndpoint.java create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventSubscriptionEndpoint.java create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/constants/EventNotificationEndPointConstants.java create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventNotificationUtils.java create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/resources/findbugs-exclude.xml create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/resources/findbugs-include.xml create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/META-INF/webapp-classloading.xml create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/WEB-INF/beans.xml create mode 100644 financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/WEB-INF/web.xml diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/pom.xml b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/pom.xml new file mode 100644 index 00000000..af3e4754 --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/pom.xml @@ -0,0 +1,169 @@ + + + + + 4.0.0 + + + financial-services-accelerator + org.wso2.financial.services.accelerator + 4.0.0-SNAPSHOT + ../../pom.xml + + + org.wso2.financial.services.accelerator.event.notification.endpoint + war + WSO2 Financial Services - Event Notification Endpoint + + + + commons-logging + commons-logging + provided + + + io.swagger + swagger-jaxrs + provided + + + javax.ws.rs + jsr311-api + + + com.google.guava + guava + + + org.yaml + snakeyaml + + + + + javax.ws.rs + javax.ws.rs-api + provided + + + org.json.wso2 + json + provided + + + org.springframework + spring-web + provided + + + org.apache.cxf + cxf-core + provided + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + com.fasterxml.jackson.core + jackson-databind + provided + + + org.wso2.carbon.identity.inbound.auth.oauth2 + org.wso2.carbon.identity.oauth + provided + + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.common + provided + + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.consent.mgt.service + provided + + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.consent.mgt.dao + provided + + + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.event.notifications.service + provided + + + + + + + org.apache.maven.plugins + maven-war-plugin + + + + + src/main/webapp + + + api#fs#event-notifications + WEB-INF/lib/slf4j-api-*.jar + + + + com.github.spotbugs + spotbugs-maven-plugin + + Max + Low + true + true + ${project.build.directory}/spotbugs + ${project.basedir}/src/main/resources/findbugs-exclude.xml + ${project.basedir}/src/main/resources/findbugs-include.xml + + + com.h3xstream.findsecbugs + findsecbugs-plugin + ${com.h3xstream.findsecbugs.version} + + + + + + analyze-compile + compile + + check + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventCreationEndpoint.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventCreationEndpoint.java new file mode 100644 index 00000000..48580315 --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventCreationEndpoint.java @@ -0,0 +1,152 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + *

+ * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.financial.services.accelerator.event.notifications.endpoint.api; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONObject; +import org.wso2.financial.services.accelerator.event.notifications.endpoint.constants.EventNotificationEndPointConstants; +import org.wso2.financial.services.accelerator.event.notifications.endpoint.util.EventNotificationUtils; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.dto.NotificationCreationDTO; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.handler.EventCreationServiceHandler; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventCreationResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +/** + * Events creation API. + */ +@Path("/") +public class EventCreationEndpoint { + + private static final Log log = LogFactory.getLog(EventCreationEndpoint.class); + private static final EventCreationServiceHandler eventCreationServiceHandler = EventNotificationUtils. + getEventNotificationCreationServiceHandler(); + private static final String specialChars = "!@#$%&*()'+,./:;<=>?[]^_`{|}"; + + /** + * This API will be used to create events. + */ + @SuppressFBWarnings({"JAXRS_ENDPOINT", "SERVLET_HEADER"}) + // Suppressed content - Endpoint + // Suppression reason - False Positive : This endpoint is secured with access control lists in the configuration + // Suppressed content - request.getHeader() + // Suppression reason - False Positive : Header is properly validated to ensure no special characters are passed + // Suppressed warning count - 4 + @POST + @Path("/create-events") + @Consumes({"application/x-www-form-urlencoded"}) + @Produces({"application/json; charset=utf-8"}) + public Response createEvents(@Context HttpServletRequest request, @Context HttpServletResponse response, + MultivaluedMap parameterMap) { + + + NotificationCreationDTO notificationCreationDTO = new NotificationCreationDTO(); + String requestData = StringUtils.EMPTY; + JSONObject notificationEvents; + + try { + //Check if the request pay load is empty + if (!parameterMap.isEmpty() && parameterMap.containsKey(EventNotificationEndPointConstants.REQUEST)) { + + requestData = parameterMap.get(EventNotificationEndPointConstants.REQUEST). + toString().replaceAll("\\\\r|\\\\n|\\r|\\n|\\[|]| ", StringUtils.EMPTY); + + byte[] decodedBytes = Base64.getDecoder().decode(requestData); + String decodedString = new String(decodedBytes, StandardCharsets.UTF_8); + notificationEvents = new JSONObject(decodedString); + log.debug("Decoded payload string : " + decodedString.replaceAll("[\r\n]", "")); + + } else { + log.error(EventNotificationEndPointConstants.MISSING_REQUEST_PAYLOAD); + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil + .getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_PAYLOAD, + EventNotificationConstants.MISSING_REQ_PAYLOAD)).build(); + } + + //check if the client id is present in the header + String clientId = request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID); + if (!StringUtils.isBlank(clientId)) { + notificationCreationDTO.setClientId(request.getHeader( + EventNotificationEndPointConstants.X_WSO2_CLIENT_ID)); + } else { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil + .getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_HEADER, + EventNotificationConstants.MISSING_HEADER_PARAM_CLIENT_ID)).build(); + } + + //check if the resource id is present in the header + String resourceId = request.getHeader(EventNotificationEndPointConstants.X_WSO2_RESOURCE_ID); + if (!StringUtils.isBlank(resourceId)) { + if (StringUtils.containsAny(resourceId, specialChars)) { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST_HEADER, + EventNotificationConstants.INVALID_CHARS_IN_HEADER_ERROR)).build(); + } + notificationCreationDTO.setResourceId(request.getHeader( + EventNotificationEndPointConstants.X_WSO2_RESOURCE_ID));; + } else { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_HEADER, + EventNotificationConstants.MISSING_HEADER_PARAM_RESOURCE_ID)).build(); + } + + //set events to notificationCreationDTO + JSONObject finalNotificationEvents = notificationEvents; + notificationEvents.keySet().forEach(eventName -> { + JSONObject eventInformation = (JSONObject) finalNotificationEvents.get(eventName); + notificationCreationDTO.setEventPayload(eventName, eventInformation); + }); + + + EventCreationResponse eventCreationResponse = eventCreationServiceHandler. + publishEvent(notificationCreationDTO); + + return EventNotificationUtils.mapEventCreationServiceResponse(eventCreationResponse); + + } catch (ClassCastException e) { + log.error(EventNotificationEndPointConstants.REQUEST_PAYLOAD_ERROR, e); + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil + .getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST_PAYLOAD, + EventNotificationEndPointConstants.REQUEST_PAYLOAD_ERROR)).build(); + } catch (FSEventNotificationException e) { + return Response.status(e.getStatus()).entity(EventNotificationServiceUtil + .getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST, + e.getMessage())).build(); + } + + } + +} diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java new file mode 100644 index 00000000..5aec5a6a --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + *

+ * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.financial.services.accelerator.event.notifications.endpoint.api; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONObject; +import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigParser; +import org.wso2.financial.services.accelerator.event.notifications.endpoint.constants.EventNotificationEndPointConstants; +import org.wso2.financial.services.accelerator.event.notifications.endpoint.util.EventNotificationUtils; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.dto.EventPollingDTO; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.handler.EventPollingServiceHandler; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventPollingResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationError; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +/** + * Aggregated Event Polling API Specification. + * + *

Swagger for Aggregated Event Polling API Specification + */ +@Path("/events") +public class EventPollingEndpoint { + + private static final Log log = LogFactory.getLog(EventCreationEndpoint.class); + private static final EventPollingServiceHandler eventPollingServiceHandler = EventNotificationUtils. + getEventPollingServiceHandler(); + + /** + * Retrieve Event Notifications Using Aggregated Polling. + */ + @SuppressFBWarnings({"JAXRS_ENDPOINT", "SERVLET_HEADER"}) + // Suppressed content - Endpoint + // Suppression reason - False Positive : This endpoint is secured with access control lists in the configuration + // Suppressed content - request.getHeader() + // Suppression reason - False Positive : Header is properly validated to ensure no special characters are passed + // Suppressed warning count - 4 + @POST + @Path("/{s:.*}") + @Consumes({"application/x-www-form-urlencoded"}) + @Produces({"application/json; charset=utf-8", "application/jose+jwe"}) + @ApiOperation(value = "Retrieve Events", tags = {"Events"}) + + public Response pollEvents(@Context HttpServletRequest request, @Context HttpServletResponse response, + MultivaluedMap parameterMap) { + + String eventPollingData; + JSONObject eventPollingRequest; + + if (!parameterMap.isEmpty() && parameterMap.containsKey(EventNotificationEndPointConstants.REQUEST)) { + + eventPollingData = parameterMap.get(EventNotificationEndPointConstants.REQUEST). + toString().replaceAll("\\\\r|\\\\n|\\r|\\n|\\[|]| ", StringUtils.EMPTY); + + if (StringUtils.isNotBlank(eventPollingData)) { + byte[] decodedBytes = Base64.getDecoder().decode(eventPollingData); + String decodedString = new String(decodedBytes, StandardCharsets.UTF_8); + try { + eventPollingRequest = new JSONObject(decodedString); + + //check if the client id is present in the header + String clientId = request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID); + if (!StringUtils.isBlank(clientId)) { + eventPollingRequest.put(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID, request. + getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID)); + } else { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil + .getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_HEADER, + EventNotificationConstants.MISSING_HEADER_PARAM_CLIENT_ID)).build(); + } + + EventPollingDTO pollingDTO = mapPollingRequestToDTO(eventPollingRequest); + EventPollingResponse eventPollingResponse = eventPollingServiceHandler. + pollEvents(pollingDTO); + + return EventNotificationUtils.mapEventPollingServiceResponse(eventPollingResponse); + + } catch (ClassCastException e) { + log.error(EventNotificationEndPointConstants.REQUEST_PAYLOAD_ERROR, e); + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil + .getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST_PAYLOAD, + EventNotificationEndPointConstants.REQUEST_PAYLOAD_ERROR)).build(); + } catch (FSEventNotificationException e) { + return Response.status(e.getStatus()).entity(EventNotificationServiceUtil + .getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST, + e.getMessage())).build(); + } + } else { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil + .getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST_PAYLOAD, + EventNotificationEndPointConstants.EMPTY_REQ_PAYLOAD)).build(); + } + } else { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil + .getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_PAYLOAD, + EventNotificationConstants.MISSING_REQ_PAYLOAD)).build(); + } + } + + /** + * This method will map the eventPollingRequest JSON to EventPollingDTO. + * @param eventPollingRequest JSON request for event polling + * @return EventPollingDTO + */ + public EventPollingDTO mapPollingRequestToDTO(JSONObject eventPollingRequest) { + + EventPollingDTO eventPollingDTO = new EventPollingDTO(); + eventPollingDTO.setClientId(eventPollingRequest.get(EventNotificationConstants.X_WSO2_CLIENT_ID).toString()); + + if (eventPollingRequest.length() == 0) { + + eventPollingDTO.setMaxEvents(FinancialServicesConfigParser.getInstance().getNumberOfSetsToReturn()); + + return eventPollingDTO; + } + + //Set acknowledged events to DTO + if (eventPollingRequest.has(EventNotificationConstants.ACK.toLowerCase(Locale.ROOT))) { + JSONArray acknowledgedEvents = (JSONArray) eventPollingRequest. + get(EventNotificationConstants.ACK.toLowerCase(Locale.ROOT)); + acknowledgedEvents.forEach((event -> { + eventPollingDTO.setAck(event.toString()); + })); + } + + //Set error events to DTO + if (eventPollingRequest.has(EventNotificationConstants.SET_ERRORS)) { + JSONObject errorEvents = (JSONObject) eventPollingRequest. + get(EventNotificationConstants.SET_ERRORS); + errorEvents.keySet().forEach(errorEvent -> { + JSONObject errorEventInformation = (JSONObject) errorEvents.get(errorEvent); + NotificationError notificationError = getNotificationError(errorEventInformation); + notificationError.setNotificationId(errorEvent); + eventPollingDTO.setErrors(errorEvent, notificationError); + }); + } + + //Set maxEvents count to return + if (eventPollingRequest.has(EventNotificationConstants.MAX_EVENTS)) { + eventPollingDTO.setMaxEvents(Integer.parseInt(eventPollingRequest. + get(EventNotificationConstants.MAX_EVENTS).toString())); + } else { + eventPollingDTO.setMaxEvents(FinancialServicesConfigParser.getInstance().getNumberOfSetsToReturn()); + } + + return eventPollingDTO; + } + + private NotificationError getNotificationError(JSONObject errorEvent) { + + NotificationError notificationError = new NotificationError(); + notificationError.setErrorCode(errorEvent.get( + EventNotificationConstants.ERROR.toLowerCase(Locale.ROOT)).toString()); + notificationError.setErrorDescription( + errorEvent.get(EventNotificationConstants.DESCRIPTION).toString()); + return notificationError; + } +} diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventSubscriptionEndpoint.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventSubscriptionEndpoint.java new file mode 100644 index 00000000..404e0e34 --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventSubscriptionEndpoint.java @@ -0,0 +1,288 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + *

+ * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.financial.services.accelerator.event.notifications.endpoint.api; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONObject; +import org.wso2.financial.services.accelerator.event.notifications.endpoint.constants.EventNotificationEndPointConstants; +import org.wso2.financial.services.accelerator.event.notifications.endpoint.util.EventSubscriptionUtils; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.dto.EventSubscriptionDTO; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.handler.EventSubscriptionServiceHandler; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventSubscriptionResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +/** + * Events Notification Subscription API. + */ +@Path("/subscription") +public class EventSubscriptionEndpoint { + private static final Log log = LogFactory.getLog(EventSubscriptionEndpoint.class); + + private static final EventSubscriptionServiceHandler eventSubscriptionServiceHandler = EventSubscriptionUtils. + getEventSubscriptionServiceHandler(); + + /** + * Register an Event Notification Subscription. + */ + @SuppressFBWarnings({"JAXRS_ENDPOINT", "SERVLET_HEADER"}) + @POST + @Path("/") + @Consumes({"application/json; charset=utf-8"}) + @Produces({"application/json; charset=utf-8"}) + @ApiOperation(value = "Create Subscriptions", tags = {" Create Subscriptions"}) + public Response registerSubscription(@Context HttpServletRequest request, @Context HttpServletResponse response) { + + //check if the client id is present in the header + String clientId = request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID); + if (StringUtils.isBlank(clientId)) { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_HEADER, + EventNotificationConstants.MISSING_HEADER_PARAM_CLIENT_ID)).build(); + } + // extract the payload from the request + try { + JSONObject requestPayload = EventSubscriptionUtils.getJSONObjectPayload(request); + EventSubscriptionDTO eventSubscriptionDTO = mapSubscriptionRequestToDTo(requestPayload); + eventSubscriptionDTO.setClientId(request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID)); + + EventSubscriptionResponse eventSubscriptionResponse = eventSubscriptionServiceHandler. + createEventSubscription(eventSubscriptionDTO); + return EventSubscriptionUtils.mapEventSubscriptionServiceResponse(eventSubscriptionResponse); + } catch (IOException e) { + log.error("Invalid Payload received", e); + return Response.status(Response.Status.BAD_REQUEST). + entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST_PAYLOAD, + EventNotificationEndPointConstants.REQUEST_PAYLOAD_ERROR)).build(); + } catch (FSEventNotificationException e) { + return Response.status(e.getStatus()).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST, e.getMessage())).build(); + } + } + + /** + * Retrieve a Single Event Subscription. + */ + @SuppressFBWarnings({"JAXRS_ENDPOINT", "SERVLET_HEADER"}) + @GET + @Path("/{subscriptionId}") + @Consumes({"application/json; charset=utf-8"}) + @Produces({"application/json; charset=utf-8"}) + public Response retrieveSubscription(@Context HttpServletRequest request, @Context HttpServletResponse response, + @Context UriInfo uriInfo) { + //check if the client id is present in the header + String clientId = request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID); + if (StringUtils.isBlank(clientId)) { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_HEADER, + EventNotificationConstants.MISSING_HEADER_PARAM_CLIENT_ID)).build(); + } + + EventSubscriptionResponse eventSubscriptionResponse = null; + try { + eventSubscriptionResponse = eventSubscriptionServiceHandler. + getEventSubscription(clientId, uriInfo.getPathParameters() + .getFirst(EventNotificationConstants.SUBSCRIPTION_ID_PARAM)); + return EventSubscriptionUtils.mapEventSubscriptionServiceResponse(eventSubscriptionResponse); + } catch (FSEventNotificationException e) { + return Response.status(e.getStatus()).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST, e.getMessage())).build(); + } + } + + /** + * Retrieve All Events Subscriptions of a Client. + */ + @SuppressFBWarnings({"JAXRS_ENDPOINT", "SERVLET_HEADER"}) + @GET + @Path("/") + @Produces({"application/json; charset=utf-8"}) + public Response retrieveAllSubscriptions(@Context HttpServletRequest request, + @Context HttpServletResponse response) { + + //check if the client id is present in the header + String clientId = request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID); + if (StringUtils.isBlank(clientId)) { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_HEADER, + EventNotificationConstants.MISSING_HEADER_PARAM_CLIENT_ID)).build(); + } + + EventSubscriptionResponse eventSubscriptionResponse = null; + try { + eventSubscriptionResponse = eventSubscriptionServiceHandler. + getAllEventSubscriptions(clientId); + + return EventSubscriptionUtils.mapEventSubscriptionServiceResponse(eventSubscriptionResponse); + } catch (FSEventNotificationException e) { + return Response.status(e.getStatus()).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST, e.getMessage())).build(); + } + } + + /** + * Retrieve All Events Subscriptions by an event type. + */ + @SuppressFBWarnings({"JAXRS_ENDPOINT", "SERVLET_HEADER"}) + @GET + @Path("/type/{eventType}") + @Produces({"application/json; charset=utf-8"}) + public Response retrieveAllSubscriptionsByEventType(@Context HttpServletRequest request, + @Context HttpServletResponse response, + @Context UriInfo uriInfo) { + + //check if the client id is present in the header + String clientId = request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID); + if (StringUtils.isBlank(clientId)) { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_HEADER, + EventNotificationConstants.MISSING_HEADER_PARAM_CLIENT_ID)).build(); + } + + EventSubscriptionResponse eventSubscriptionResponse = null; + try { + eventSubscriptionResponse = eventSubscriptionServiceHandler.getEventSubscriptionsByEventType(clientId, + uriInfo.getPathParameters().getFirst(EventNotificationConstants.EVENT_TYPE_PARAM)); + return EventSubscriptionUtils.mapEventSubscriptionServiceResponse(eventSubscriptionResponse); + } catch (FSEventNotificationException e) { + return Response.status(e.getStatus()).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST, e.getMessage())).build(); + } + } + + /** + * Update an Event Subscription. + */ + @SuppressFBWarnings({"JAXRS_ENDPOINT", "SERVLET_HEADER"}) + @PUT + @Path("/{subscriptionId}") + @Consumes({"application/json; charset=utf-8"}) + @Produces({"application/json; charset=utf-8"}) + public Response updateSubscription(@Context HttpServletRequest request, @Context HttpServletResponse response, + @Context UriInfo uriInfo) { + + //check if the client id is present in the header + String clientId = request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID); + if (StringUtils.isBlank(clientId)) { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_HEADER, + EventNotificationConstants.MISSING_HEADER_PARAM_CLIENT_ID)).build(); + } + + // extract the payload from the request + try { + JSONObject requestPayload = EventSubscriptionUtils.getJSONObjectPayload(request); + EventSubscriptionDTO eventSubscriptionDTO = mapSubscriptionRequestToDTo(requestPayload); + eventSubscriptionDTO.setClientId(request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID)); + + eventSubscriptionDTO.setSubscriptionId(uriInfo.getPathParameters() + .getFirst(EventNotificationConstants.SUBSCRIPTION_ID_PARAM)); + EventSubscriptionResponse eventSubscriptionResponse = eventSubscriptionServiceHandler. + updateEventSubscription(eventSubscriptionDTO); + return EventSubscriptionUtils.mapEventSubscriptionServiceResponse(eventSubscriptionResponse); + } catch (IOException e) { + log.error("Invalid Payload received", e); + return Response.status(Response.Status.BAD_REQUEST). + entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST_PAYLOAD, + EventNotificationEndPointConstants.REQUEST_PAYLOAD_ERROR)).build(); + } catch (FSEventNotificationException e) { + return Response.status(e.getStatus()).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST, e.getMessage())).build(); + } + } + + /** + * Delete an Event Subscription. + */ + @SuppressFBWarnings({"JAXRS_ENDPOINT", "SERVLET_HEADER"}) + @DELETE + @Path("/{subscriptionId}") + @Consumes({"application/json; charset=utf-8"}) + @Produces({"application/json; charset=utf-8"}) + public Response deleteSubscription(@Context HttpServletRequest request, @Context HttpServletResponse response, + @Context UriInfo uriInfo) { + //check if the client id is present in the header + String clientId = request.getHeader(EventNotificationEndPointConstants.X_WSO2_CLIENT_ID); + if (StringUtils.isBlank(clientId)) { + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.MISSING_REQUEST_HEADER, + EventNotificationConstants.MISSING_HEADER_PARAM_CLIENT_ID)).build(); + } + + EventSubscriptionResponse eventSubscriptionResponse = null; + try { + eventSubscriptionResponse = eventSubscriptionServiceHandler.deleteEventSubscription(clientId, + uriInfo.getPathParameters().getFirst(EventNotificationConstants.SUBSCRIPTION_ID_PARAM)); + return EventSubscriptionUtils.mapEventSubscriptionServiceResponse(eventSubscriptionResponse); + } catch (FSEventNotificationException e) { + return Response.status(e.getStatus()).entity(EventNotificationServiceUtil. + getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST, e.getMessage())).build(); + } + } + + /** + * Method to map the Subscription Request to DTO. + * @param requestPayload Subscription Request Payload + * @return EventSubscriptionDTO + */ + private EventSubscriptionDTO mapSubscriptionRequestToDTo(JSONObject requestPayload) { + EventSubscriptionDTO eventSubscriptionDTO = new EventSubscriptionDTO(); + eventSubscriptionDTO.setCallbackUrl(requestPayload.has(EventNotificationConstants.CALLBACK_URL_PARAM) ? + requestPayload.getString(EventNotificationConstants.CALLBACK_URL_PARAM) : null); + eventSubscriptionDTO.setSpecVersion(requestPayload.has(EventNotificationConstants.VERSION_PARAM) ? + requestPayload.getString(EventNotificationConstants.VERSION_PARAM) : null); + eventSubscriptionDTO.setRequestData(requestPayload.toString()); + + List eventTypesList = new ArrayList<>(); + if (requestPayload.has(EventNotificationConstants.EVENT_TYPES_PARAM)) { + JSONArray eventTypes = requestPayload.getJSONArray(EventNotificationConstants.EVENT_TYPES_PARAM); + eventTypes.iterator().forEachRemaining(eventType -> { + eventTypesList.add(eventType.toString()); + }); + eventSubscriptionDTO.setEventTypes(eventTypesList); + } + return eventSubscriptionDTO; + } + +} diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/constants/EventNotificationEndPointConstants.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/constants/EventNotificationEndPointConstants.java new file mode 100644 index 00000000..8d85926b --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/constants/EventNotificationEndPointConstants.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + *

+ * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.financial.services.accelerator.event.notifications.endpoint.constants; + +/** + * Constants in Endpoint. + */ +public class EventNotificationEndPointConstants { + public static final String X_WSO2_CLIENT_ID = "x-wso2-client-id"; + public static final String X_WSO2_RESOURCE_ID = "x-wso2-resource-id"; + public static final String REQUEST = "request"; + public static final String EVENT_CREATION_ERROR_RESPONSE = "Event Notification Creation error"; + public static final String REQUEST_PAYLOAD_ERROR = "Error in the request payload"; + public static final String EMPTY_REQ_PAYLOAD = "Request payload cannot be empty"; + public static final String INVALID_REQUEST = "invalid_request"; + public static final String INVALID_REQUEST_PAYLOAD = "invalid_request_payload"; + public static final String MISSING_REQUEST_PAYLOAD = "missing_request_payload"; + public static final String INVALID_REQUEST_HEADER = "invalid_request_header"; + public static final String MISSING_REQUEST_HEADER = "missing_request_header"; +} diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventNotificationUtils.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventNotificationUtils.java new file mode 100644 index 00000000..23a34898 --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventNotificationUtils.java @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + *

+ * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.financial.services.accelerator.event.notifications.endpoint.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigParser; +import org.wso2.financial.services.accelerator.common.constant.FinancialServicesConstants; +import org.wso2.financial.services.accelerator.common.util.FinancialServicesUtils; +import org.wso2.financial.services.accelerator.event.notifications.endpoint.constants.EventNotificationEndPointConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.handler.EventCreationServiceHandler; +import org.wso2.financial.services.accelerator.event.notifications.service.handler.EventPollingServiceHandler; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventCreationResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventPollingResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +import javax.ws.rs.core.Response; + +/** + * This class will have util methods needed for event notifications. + */ +public class EventNotificationUtils { + + private static final Log log = LogFactory.getLog(EventNotificationUtils.class); + + /** + * This method is to get the event creation service handler as per the config. + * @return EventCreationServiceHandler + */ + public static EventCreationServiceHandler getEventNotificationCreationServiceHandler() { + + return (EventCreationServiceHandler) + FinancialServicesUtils.getClassInstanceFromFQN(FinancialServicesConfigParser.getInstance(). + getConfiguration().get(FinancialServicesConstants.EVENT_CREATION_HANDLER).toString()); + } + + /** + * This method is to get the event polling service handler as per the config. + * @return EventPollingServiceHandler + */ + public static EventPollingServiceHandler getEventPollingServiceHandler() { + + return (EventPollingServiceHandler) + FinancialServicesUtils.getClassInstanceFromFQN(FinancialServicesConfigParser.getInstance(). + getConfiguration().get(FinancialServicesConstants.EVENT_POLLING_HANDLER).toString()); + } + + /** + * Method to map the Event Creation Service Response to API response. + * @param eventCreationResponse EventCreationResponse + * @return Response + */ + public static Response mapEventCreationServiceResponse(EventCreationResponse eventCreationResponse) { + + if (EventNotificationConstants.CREATED.equals(eventCreationResponse.getStatus())) { + + return Response.status(Response.Status.CREATED) + .entity(eventCreationResponse.getResponseBody().toString()).build(); + + } + + return Response.status(Response.Status.BAD_REQUEST).entity(EventNotificationServiceUtil.getErrorDTO( + EventNotificationEndPointConstants.INVALID_REQUEST, + EventNotificationEndPointConstants.EVENT_CREATION_ERROR_RESPONSE)).build(); + } + + /** + * Method to map Event Polling Service to API response. + * @param eventPollingResponse EventPollingResponse + * @return Response + */ + public static Response mapEventPollingServiceResponse(EventPollingResponse eventPollingResponse) { + + String responseBody = eventPollingResponse.getResponseBody().toString(); + if (EventNotificationConstants.OK.equals(eventPollingResponse.getStatus())) { + return Response.status(Response.Status.OK).entity(responseBody).build(); + } else if (EventNotificationConstants.NOT_FOUND.equals(eventPollingResponse.getStatus())) { + return Response.status(Response.Status.NOT_FOUND).entity(responseBody).build(); + } + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); + } + + /** + * Get mapped Response.Status for the given status value. + * @param status status value + * @return Mapped Response.Status + */ + private static Response.Status getErrorResponseStatus(String status) { + + if (EventNotificationConstants.NOT_FOUND.equals(status)) { + return Response.Status.NOT_FOUND; + } else if (EventNotificationConstants.BAD_REQUEST.equals(status)) { + return Response.Status.BAD_REQUEST; + } else { + return Response.Status.INTERNAL_SERVER_ERROR; + } + } +} diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java new file mode 100644 index 00000000..a690ce6a --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.financial.services.accelerator.event.notifications.endpoint.util; + +import org.apache.commons.io.IOUtils; +import org.json.JSONObject; +import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigParser; +import org.wso2.financial.services.accelerator.common.constant.FinancialServicesConstants; +import org.wso2.financial.services.accelerator.common.util.FinancialServicesUtils; +import org.wso2.financial.services.accelerator.event.notifications.service.handler.EventSubscriptionServiceHandler; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventSubscriptionResponse; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Response; + +/** + * Events Notification Subscription API Utils. + */ +public class EventSubscriptionUtils { + + /** + * Extract string payload from request object. + */ + public static EventSubscriptionServiceHandler getEventSubscriptionServiceHandler() { + + return (EventSubscriptionServiceHandler) + FinancialServicesUtils.getClassInstanceFromFQN(FinancialServicesConfigParser.getInstance() + .getConfiguration().get(FinancialServicesConstants.EVENT_SUBSCRIPTION_HANDLER).toString()); + } + + /** + * Extract string payload from request object. + * + * @param request The request object + * @return String payload + */ + public static JSONObject getJSONObjectPayload(HttpServletRequest request) throws IOException { + return new JSONObject(IOUtils.toString(request.getInputStream())); + } + + /** + * Method to map the Event Creation Service Response to API response. + * + * @param eventSubscriptionResponse Event Subscription Response + * @return Response + */ + public static Response mapEventSubscriptionServiceResponse(EventSubscriptionResponse eventSubscriptionResponse) { + if (eventSubscriptionResponse.getResponseBody() != null) { + return Response.status(eventSubscriptionResponse.getResponseStatus()) + .entity(eventSubscriptionResponse.getResponseBody().toString()) + .build(); + } else { + return Response.status(eventSubscriptionResponse.getResponseStatus()) + .build(); + } + } +} diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/resources/findbugs-exclude.xml b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/resources/findbugs-exclude.xml new file mode 100644 index 00000000..9fa42f18 --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/resources/findbugs-exclude.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/resources/findbugs-include.xml b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/resources/findbugs-include.xml new file mode 100644 index 00000000..c6b932b1 --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/resources/findbugs-include.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/META-INF/webapp-classloading.xml b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/META-INF/webapp-classloading.xml new file mode 100644 index 00000000..9359bbf9 --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/META-INF/webapp-classloading.xml @@ -0,0 +1,35 @@ + + + + + + + + + false + + + CXF3,Carbon + diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/WEB-INF/beans.xml b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 00000000..11ec5ea8 --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/WEB-INF/web.xml b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..64c0f57c --- /dev/null +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,71 @@ + + + + + + + WSO2 Financial Services - Event Notification API + WSO2 Financial Services - Event Notification API + + + contextConfigLocation + WEB-INF/beans.xml + + + + HttpHeaderSecurityFilter + org.apache.catalina.filters.HttpHeaderSecurityFilter + + hstsEnabled + false + + + + + HttpHeaderSecurityFilter + * + + + + + org.springframework.web.context.ContextLoaderListener + + + + + CXFServlet + + org.apache.cxf.transport.servlet.CXFServlet + + 1 + + + + CXFServlet + /* + + + + 60 + + + diff --git a/financial-services-accelerator/pom.xml b/financial-services-accelerator/pom.xml index c2b8ba0d..243e47c4 100644 --- a/financial-services-accelerator/pom.xml +++ b/financial-services-accelerator/pom.xml @@ -41,5 +41,6 @@ components/org.wso2.financial.services.accelerator.gateway internal-webapps/org.wso2.financial.services.accelerator.consent.mgt.endpoint internal-webapps/org.wso2.financial.services.accelerator.authentication.endpoint + internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint diff --git a/pom.xml b/pom.xml index 879d236b..e09976aa 100644 --- a/pom.xml +++ b/pom.xml @@ -383,6 +383,11 @@ jackson-databind ${jackson.databinding.version} + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.databinding.version} + org.springframework spring-web @@ -506,6 +511,16 @@ org.wso2.financial.services.accelerator.consent.mgt.extensions ${project.version} + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.identity.extensions + ${project.version} + + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.event.notifications.service + ${project.version} + org.testng @@ -580,9 +595,9 @@ 1.0.0.wso2v3 1.6.1 2.1.1 - 5.1.2.RELEASE + 5.3.39-wso2v1 2.5 - 3.3.7 + 3.5.9 1.2 1.7.21 3.0.0.v201112011016 From bd498c69e4f1f092489a4585bc4a8b1c110bef48 Mon Sep 17 00:00:00 2001 From: ashirwadadayarathne Date: Mon, 9 Dec 2024 14:26:26 +0530 Subject: [PATCH 2/3] Adding event endpoint configs --- .../repository/resources/wso2is-7.0.0-deployment.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/financial-services-accelerator/accelerators/fs-is/repository/resources/wso2is-7.0.0-deployment.toml b/financial-services-accelerator/accelerators/fs-is/repository/resources/wso2is-7.0.0-deployment.toml index a5944ecf..27696cce 100644 --- a/financial-services-accelerator/accelerators/fs-is/repository/resources/wso2is-7.0.0-deployment.toml +++ b/financial-services-accelerator/accelerators/fs-is/repository/resources/wso2is-7.0.0-deployment.toml @@ -218,6 +218,13 @@ context = "(.*)/fs/authenticationendpoint/(.*)" http_method = "all" secure = "false" +[[resource.access_control]] +allowed_auth_handlers = ["BasicAuthentication"] +context = "(.*)/api/fs/event-notifications/(.*)" +http_method = "all" +permissions = ["/permission/admin"] +secure = "true" + [[resource.access_control]] context="(.*)/scim2/Me" secure=true From 1f79f1298f086fcd945a3516570d04781c3fec0e Mon Sep 17 00:00:00 2001 From: ashirwadadayarathne Date: Thu, 12 Dec 2024 10:09:12 +0530 Subject: [PATCH 3/3] Fixed review comments --- .../pom.xml | 2 +- .../endpoint/api/EventCreationEndpoint.java | 20 ++++++++++++++----- .../endpoint/api/EventPollingEndpoint.java | 15 +++++++++++--- .../api/EventSubscriptionEndpoint.java | 13 ++++++++++-- .../endpoint/util/EventNotificationUtils.java | 4 ++++ .../endpoint/util/EventSubscriptionUtils.java | 4 ++++ 6 files changed, 47 insertions(+), 11 deletions(-) diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/pom.xml b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/pom.xml index af3e4754..344acd07 100644 --- a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/pom.xml +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/pom.xml @@ -28,7 +28,7 @@ ../../pom.xml - org.wso2.financial.services.accelerator.event.notification.endpoint + org.wso2.financial.services.accelerator.event.notifications.endpoint war WSO2 Financial Services - Event Notification Endpoint diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventCreationEndpoint.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventCreationEndpoint.java index 48580315..b1116214 100644 --- a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventCreationEndpoint.java +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventCreationEndpoint.java @@ -52,9 +52,19 @@ public class EventCreationEndpoint { private static final Log log = LogFactory.getLog(EventCreationEndpoint.class); - private static final EventCreationServiceHandler eventCreationServiceHandler = EventNotificationUtils. - getEventNotificationCreationServiceHandler(); + private final EventCreationServiceHandler eventCreationServiceHandler; private static final String specialChars = "!@#$%&*()'+,./:;<=>?[]^_`{|}"; + private static final String illegalChars = "\\\\r|\\\\n|\\r|\\n|\\[|]| "; + + public EventCreationEndpoint() { + + eventCreationServiceHandler = EventNotificationUtils.getEventNotificationCreationServiceHandler(); + } + + public EventCreationEndpoint(EventCreationServiceHandler handler) { + + eventCreationServiceHandler = handler; + } /** * This API will be used to create events. @@ -82,7 +92,7 @@ public Response createEvents(@Context HttpServletRequest request, @Context HttpS if (!parameterMap.isEmpty() && parameterMap.containsKey(EventNotificationEndPointConstants.REQUEST)) { requestData = parameterMap.get(EventNotificationEndPointConstants.REQUEST). - toString().replaceAll("\\\\r|\\\\n|\\r|\\n|\\[|]| ", StringUtils.EMPTY); + toString().replaceAll(illegalChars, StringUtils.EMPTY); byte[] decodedBytes = Base64.getDecoder().decode(requestData); String decodedString = new String(decodedBytes, StandardCharsets.UTF_8); @@ -124,9 +134,8 @@ public Response createEvents(@Context HttpServletRequest request, @Context HttpS } //set events to notificationCreationDTO - JSONObject finalNotificationEvents = notificationEvents; notificationEvents.keySet().forEach(eventName -> { - JSONObject eventInformation = (JSONObject) finalNotificationEvents.get(eventName); + JSONObject eventInformation = notificationEvents.getJSONObject(eventName); notificationCreationDTO.setEventPayload(eventName, eventInformation); }); @@ -142,6 +151,7 @@ public Response createEvents(@Context HttpServletRequest request, @Context HttpS .getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST_PAYLOAD, EventNotificationEndPointConstants.REQUEST_PAYLOAD_ERROR)).build(); } catch (FSEventNotificationException e) { + log.error(EventNotificationEndPointConstants.EVENT_CREATION_ERROR_RESPONSE, e); return Response.status(e.getStatus()).entity(EventNotificationServiceUtil .getErrorDTO(EventNotificationEndPointConstants.INVALID_REQUEST, e.getMessage())).build(); diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java index 5aec5a6a..c6c3c171 100644 --- a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventPollingEndpoint.java @@ -58,9 +58,18 @@ @Path("/events") public class EventPollingEndpoint { - private static final Log log = LogFactory.getLog(EventCreationEndpoint.class); - private static final EventPollingServiceHandler eventPollingServiceHandler = EventNotificationUtils. - getEventPollingServiceHandler(); + private static final Log log = LogFactory.getLog(EventPollingEndpoint.class); + private EventPollingServiceHandler eventPollingServiceHandler; + + public EventPollingEndpoint() { + + eventPollingServiceHandler = EventNotificationUtils.getEventPollingServiceHandler(); + } + + public EventPollingEndpoint(EventPollingServiceHandler handler) { + + eventPollingServiceHandler = handler; + } /** * Retrieve Event Notifications Using Aggregated Polling. diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventSubscriptionEndpoint.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventSubscriptionEndpoint.java index 404e0e34..324e2a81 100644 --- a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventSubscriptionEndpoint.java +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/api/EventSubscriptionEndpoint.java @@ -58,8 +58,17 @@ public class EventSubscriptionEndpoint { private static final Log log = LogFactory.getLog(EventSubscriptionEndpoint.class); - private static final EventSubscriptionServiceHandler eventSubscriptionServiceHandler = EventSubscriptionUtils. - getEventSubscriptionServiceHandler(); + private final EventSubscriptionServiceHandler eventSubscriptionServiceHandler; + + public EventSubscriptionEndpoint() { + + eventSubscriptionServiceHandler = EventSubscriptionUtils.getEventSubscriptionServiceHandler(); + } + + public EventSubscriptionEndpoint(EventSubscriptionServiceHandler handler) { + + eventSubscriptionServiceHandler = handler; + } /** * Register an Event Notification Subscription. diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventNotificationUtils.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventNotificationUtils.java index 23a34898..c706bcc4 100644 --- a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventNotificationUtils.java +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventNotificationUtils.java @@ -40,6 +40,10 @@ public class EventNotificationUtils { private static final Log log = LogFactory.getLog(EventNotificationUtils.class); + private EventNotificationUtils() { + + } + /** * This method is to get the event creation service handler as per the config. * @return EventCreationServiceHandler diff --git a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java index a690ce6a..67655ba3 100644 --- a/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java +++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/src/main/java/org/wso2/financial/services/accelerator/event/notifications/endpoint/util/EventSubscriptionUtils.java @@ -36,6 +36,10 @@ */ public class EventSubscriptionUtils { + private EventSubscriptionUtils() { + + } + /** * Extract string payload from request object. */