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
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..344acd07
--- /dev/null
+++ b/financial-services-accelerator/internal-webapps/org.wso2.financial.services.accelerator.event.notifications.endpoint/pom.xml
@@ -0,0 +1,169 @@
+
+
+
+
+ * 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 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. + */ + @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(illegalChars, 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 + notificationEvents.keySet().forEach(eventName -> { + JSONObject eventInformation = notificationEvents.getJSONObject(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) { + 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 new file mode 100644 index 00000000..c6c3c171 --- /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,203 @@ +/** + * 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(EventPollingEndpoint.class); + private EventPollingServiceHandler eventPollingServiceHandler; + + public EventPollingEndpoint() { + + eventPollingServiceHandler = EventNotificationUtils.getEventPollingServiceHandler(); + } + + public EventPollingEndpoint(EventPollingServiceHandler handler) { + + eventPollingServiceHandler = handler; + } + + /** + * 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..324e2a81 --- /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,297 @@ +/** + * 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 final EventSubscriptionServiceHandler eventSubscriptionServiceHandler;
+
+ public EventSubscriptionEndpoint() {
+
+ eventSubscriptionServiceHandler = EventSubscriptionUtils.getEventSubscriptionServiceHandler();
+ }
+
+ public EventSubscriptionEndpoint(EventSubscriptionServiceHandler handler) {
+
+ eventSubscriptionServiceHandler = handler;
+ }
+
+ /**
+ * 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
+ * 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..c706bcc4
--- /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,119 @@
+/**
+ * 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);
+
+ private EventNotificationUtils() {
+
+ }
+
+ /**
+ * 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..67655ba3
--- /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,79 @@
+/**
+ * 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 {
+
+ private 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 @@
+
+
+
+