diff --git a/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/mssql.sql b/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/mssql.sql index d0c43ab8..58965e86 100644 --- a/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/mssql.sql +++ b/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/mssql.sql @@ -21,7 +21,7 @@ -- Since the database systems does not support adding default unix time to the database columns, the default data -- storing is handled within the database querieS. -CREATE TABLE OB_NOTIFICATION ( +CREATE TABLE FS_NOTIFICATION ( NOTIFICATION_ID varchar(36) NOT NULL, CLIENT_ID varchar(255) NOT NULL, RESOURCE_ID varchar(255) NOT NULL, @@ -30,24 +30,24 @@ CREATE TABLE OB_NOTIFICATION ( PRIMARY KEY (NOTIFICATION_ID) ); -CREATE TABLE OB_NOTIFICATION_EVENT ( +CREATE TABLE FS_NOTIFICATION_EVENT ( EVENT_ID int NOT NULL IDENTITY, NOTIFICATION_ID varchar(36) NOT NULL, EVENT_TYPE varchar(200) NOT NULL, EVENT_INFO varchar(1000) NOT NULL, PRIMARY KEY (EVENT_ID), - CONSTRAINT FK_NotificationEvent FOREIGN KEY (NOTIFICATION_ID) REFERENCES OB_NOTIFICATION(NOTIFICATION_ID) + CONSTRAINT FK_NotificationEvent FOREIGN KEY (NOTIFICATION_ID) REFERENCES FS_NOTIFICATION(NOTIFICATION_ID) ); -CREATE TABLE OB_NOTIFICATION_ERROR ( +CREATE TABLE FS_NOTIFICATION_ERROR ( NOTIFICATION_ID varchar(36) NOT NULL, ERROR_CODE varchar(255) NOT NULL, DESCRIPTION varchar(255) NOT NULL, PRIMARY KEY (NOTIFICATION_ID), - CONSTRAINT FK_NotificationError FOREIGN KEY (NOTIFICATION_ID) REFERENCES OB_NOTIFICATION(NOTIFICATION_ID) + CONSTRAINT FK_NotificationError FOREIGN KEY (NOTIFICATION_ID) REFERENCES FS_NOTIFICATION(NOTIFICATION_ID) ); -CREATE TABLE OB_NOTIFICATION_SUBSCRIPTION ( +CREATE TABLE FS_NOTIFICATION_SUBSCRIPTION ( SUBSCRIPTION_ID varchar(36) NOT NULL, CLIENT_ID varchar(255) NOT NULL, REQUEST JSON NOT NULL, @@ -58,9 +58,9 @@ CREATE TABLE OB_NOTIFICATION_SUBSCRIPTION ( PRIMARY KEY (SUBSCRIPTION_ID) ); -CREATE TABLE OB_NOTIFICATION_SUBSCRIBED_EVENTS ( +CREATE TABLE FS_NOTIFICATION_SUBSCRIBED_EVENTS ( SUBSCRIPTION_ID varchar(36) NOT NULL, EVENT_TYPE varchar(255) NOT NULL, PRIMARY KEY (SUBSCRIPTION_ID, EVENT_TYPE), - CONSTRAINT FK_NotificationSubEvents FOREIGN KEY (SUBSCRIPTION_ID) REFERENCES OB_NOTIFICATION_SUBSCRIPTION(SUBSCRIPTION_ID) + CONSTRAINT FK_NotificationSubEvents FOREIGN KEY (SUBSCRIPTION_ID) REFERENCES FS_NOTIFICATION_SUBSCRIPTION(SUBSCRIPTION_ID) ); diff --git a/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/mysql.sql b/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/mysql.sql index 30201693..4cce33d9 100644 --- a/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/mysql.sql +++ b/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/mysql.sql @@ -23,7 +23,7 @@ -- For event notifications feature run the following queries against the openbank_openbankingdb-- -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION ( NOTIFICATION_ID varchar(36) NOT NULL, CLIENT_ID varchar(255) NOT NULL, RESOURCE_ID varchar(255) NOT NULL, @@ -33,26 +33,26 @@ CREATE TABLE IF NOT EXISTS OB_NOTIFICATION ( ) ENGINE=InnoDB; -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_EVENT ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION_EVENT ( EVENT_ID int(11) NOT NULL AUTO_INCREMENT, NOTIFICATION_ID varchar(36) NOT NULL, EVENT_TYPE varchar(200) NOT NULL, EVENT_INFO varchar(1000) NOT NULL, PRIMARY KEY (EVENT_ID), - CONSTRAINT FK_NotificationEvent FOREIGN KEY (NOTIFICATION_ID) REFERENCES OB_NOTIFICATION(NOTIFICATION_ID) + CONSTRAINT FK_NotificationEvent FOREIGN KEY (NOTIFICATION_ID) REFERENCES FS_NOTIFICATION(NOTIFICATION_ID) ) ENGINE=InnoDB; -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_ERROR ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION_ERROR ( NOTIFICATION_ID varchar(36) NOT NULL, ERROR_CODE varchar(255) NOT NULL, DESCRIPTION varchar(255) NOT NULL, PRIMARY KEY (NOTIFICATION_ID), - CONSTRAINT FK_NotificationError FOREIGN KEY (NOTIFICATION_ID) REFERENCES OB_NOTIFICATION(NOTIFICATION_ID) + CONSTRAINT FK_NotificationError FOREIGN KEY (NOTIFICATION_ID) REFERENCES FS_NOTIFICATION(NOTIFICATION_ID) ) ENGINE=InnoDB; -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_SUBSCRIPTION ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION_SUBSCRIPTION ( SUBSCRIPTION_ID varchar(36) NOT NULL, CLIENT_ID varchar(255) NOT NULL, REQUEST JSON NOT NULL, @@ -64,10 +64,10 @@ CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_SUBSCRIPTION ( ) ENGINE=InnoDB; -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_SUBSCRIBED_EVENTS ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION_SUBSCRIBED_EVENTS ( SUBSCRIPTION_ID varchar(36) NOT NULL, EVENT_TYPE varchar(255) NOT NULL, PRIMARY KEY (SUBSCRIPTION_ID, EVENT_TYPE), - CONSTRAINT FK_NotificationSubEvents FOREIGN KEY (SUBSCRIPTION_ID) REFERENCES OB_NOTIFICATION_SUBSCRIPTION(SUBSCRIPTION_ID) + CONSTRAINT FK_NotificationSubEvents FOREIGN KEY (SUBSCRIPTION_ID) REFERENCES FS_NOTIFICATION_SUBSCRIPTION(SUBSCRIPTION_ID) ) ENGINE=InnoDB; diff --git a/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/oracle.sql b/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/oracle.sql index 26a374e4..0d5341ea 100644 --- a/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/oracle.sql +++ b/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/oracle.sql @@ -19,9 +19,9 @@ -- All the data related to time are stored in unix time stamp and therefore, the data types for the time related data -- are represented in BIGINT. -- Since the database systems does not support adding default unix time to the database columns, the default data --- storing is handled within the database querieS. +-- storing is handled within the database queries. -CREATE TABLE OB_NOTIFICATION ( +CREATE TABLE FS_NOTIFICATION ( NOTIFICATION_ID varchar2(36) NOT NULL, CLIENT_ID varchar2(255) NOT NULL, RESOURCE_ID varchar2(255) NOT NULL, @@ -30,34 +30,34 @@ CREATE TABLE OB_NOTIFICATION ( PRIMARY KEY (NOTIFICATION_ID) ); -CREATE TABLE OB_NOTIFICATION_EVENT ( +CREATE TABLE FS_NOTIFICATION_EVENT ( EVENT_ID number(10) NOT NULL, NOTIFICATION_ID varchar2(36) NOT NULL, EVENT_TYPE varchar2(200) NOT NULL, EVENT_INFO varchar2(1000) NOT NULL, PRIMARY KEY (EVENT_ID), - CONSTRAINT FK_NotificationEvent FOREIGN KEY (NOTIFICATION_ID) REFERENCES OB_NOTIFICATION(NOTIFICATION_ID) + CONSTRAINT FK_NotificationEvent FOREIGN KEY (NOTIFICATION_ID) REFERENCES FS_NOTIFICATION(NOTIFICATION_ID) ); -- Generate ID using sequence and trigger -CREATE SEQUENCE OB_NOTIFICATION_EVENT_seq START WITH 1 INCREMENT BY 1; +CREATE SEQUENCE FS_NOTIFICATION_EVENT_seq START WITH 1 INCREMENT BY 1; -CREATE OR REPLACE TRIGGER OB_NOTIFICATION_EVENT_seq_tr - BEFORE INSERT ON OB_NOTIFICATION_EVENT FOR EACH ROW +CREATE OR REPLACE TRIGGER FS_NOTIFICATION_EVENT_seq_tr + BEFORE INSERT ON FS_NOTIFICATION_EVENT FOR EACH ROW WHEN (NEW.EVENT_ID IS NULL) BEGIN - SELECT OB_NOTIFICATION_EVENT_seq.NEXTVAL INTO :NEW.EVENT_ID FROM DUAL; + SELECT FS_NOTIFICATION_EVENT_seq.NEXTVAL INTO :NEW.EVENT_ID FROM DUAL; END; -CREATE TABLE OB_NOTIFICATION_ERROR ( +CREATE TABLE FS_NOTIFICATION_ERROR ( NOTIFICATION_ID varchar2(36) NOT NULL, ERROR_CODE varchar2(255) NOT NULL, DESCRIPTION varchar2(255) NOT NULL, PRIMARY KEY (NOTIFICATION_ID), - CONSTRAINT FK_NotificationError FOREIGN KEY (NOTIFICATION_ID) REFERENCES OB_NOTIFICATION(NOTIFICATION_ID) + CONSTRAINT FK_NotificationError FOREIGN KEY (NOTIFICATION_ID) REFERENCES FS_NOTIFICATION(NOTIFICATION_ID) ) -CREATE TABLE OB_NOTIFICATION_SUBSCRIPTION ( +CREATE TABLE FS_NOTIFICATION_SUBSCRIPTION ( SUBSCRIPTION_ID varchar(36) NOT NULL, CLIENT_ID varchar(255) NOT NULL, REQUEST JSON NOT NULL, @@ -68,9 +68,9 @@ CREATE TABLE OB_NOTIFICATION_SUBSCRIPTION ( PRIMARY KEY (SUBSCRIPTION_ID) ); -CREATE TABLE OB_NOTIFICATION_SUBSCRIBED_EVENTS ( +CREATE TABLE FS_NOTIFICATION_SUBSCRIBED_EVENTS ( SUBSCRIPTION_ID varchar(36) NOT NULL, EVENT_TYPE varchar(255) NOT NULL, PRIMARY KEY (SUBSCRIPTION_ID, EVENT_TYPE), - CONSTRAINT FK_NotificationSubEvents FOREIGN KEY (SUBSCRIPTION_ID) REFERENCES OB_NOTIFICATION_SUBSCRIPTION(SUBSCRIPTION_ID) + CONSTRAINT FK_NotificationSubEvents FOREIGN KEY (SUBSCRIPTION_ID) REFERENCES FS_NOTIFICATION_SUBSCRIPTION(SUBSCRIPTION_ID) ); diff --git a/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/postgresql.sql b/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/postgresql.sql index 86d3d7c3..629230ff 100644 --- a/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/postgresql.sql +++ b/financial-services-accelerator/accelerators/fs-is/carbon-home/dbscripts/financial-services/event-notifications/postgresql.sql @@ -23,7 +23,7 @@ -- For event notifications feature run the following queries against the openbank_openbankingdb-- -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION ( NOTIFICATION_ID varchar(36) NOT NULL, CLIENT_ID varchar(255) NOT NULL, RESOURCE_ID varchar(255) NOT NULL, @@ -32,23 +32,23 @@ CREATE TABLE IF NOT EXISTS OB_NOTIFICATION ( PRIMARY KEY (NOTIFICATION_ID) ); -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_EVENT ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION_EVENT ( EVENT_ID SERIAL PRIMARY KEY, NOTIFICATION_ID varchar(36) NOT NULL, EVENT_TYPE varchar(200) NOT NULL, EVENT_INFO varchar(1000) NOT NULL, - CONSTRAINT FK_NotificationEvent FOREIGN KEY (NOTIFICATION_ID) REFERENCES OB_NOTIFICATION(NOTIFICATION_ID) + CONSTRAINT FK_NotificationEvent FOREIGN KEY (NOTIFICATION_ID) REFERENCES FS_NOTIFICATION(NOTIFICATION_ID) ); -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_ERROR ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION_ERROR ( NOTIFICATION_ID varchar(36) NOT NULL, ERROR_CODE varchar(255) NOT NULL, DESCRIPTION varchar(255) NOT NULL, PRIMARY KEY (NOTIFICATION_ID), - CONSTRAINT FK_NotificationError FOREIGN KEY (NOTIFICATION_ID) REFERENCES OB_NOTIFICATION(NOTIFICATION_ID) + CONSTRAINT FK_NotificationError FOREIGN KEY (NOTIFICATION_ID) REFERENCES FS_NOTIFICATION(NOTIFICATION_ID) ); -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_SUBSCRIPTION ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION_SUBSCRIPTION ( SUBSCRIPTION_ID varchar(36) NOT NULL, CLIENT_ID varchar(255) NOT NULL, REQUEST JSON NOT NULL, @@ -59,9 +59,9 @@ CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_SUBSCRIPTION ( PRIMARY KEY (SUBSCRIPTION_ID) ); -CREATE TABLE IF NOT EXISTS OB_NOTIFICATION_SUBSCRIBED_EVENTS ( +CREATE TABLE IF NOT EXISTS FS_NOTIFICATION_SUBSCRIBED_EVENTS ( SUBSCRIPTION_ID varchar(36) NOT NULL, EVENT_TYPE varchar(255) NOT NULL, PRIMARY KEY (SUBSCRIPTION_ID, EVENT_TYPE), - CONSTRAINT FK_NotificationSubEvents FOREIGN KEY (SUBSCRIPTION_ID) REFERENCES OB_NOTIFICATION_SUBSCRIPTION(SUBSCRIPTION_ID) + CONSTRAINT FK_NotificationSubEvents FOREIGN KEY (SUBSCRIPTION_ID) REFERENCES FS_NOTIFICATION_SUBSCRIPTION(SUBSCRIPTION_ID) ); diff --git a/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/components/lib/quartz-2.3.2.jar b/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/components/lib/quartz-2.3.2.jar new file mode 100644 index 00000000..8b738828 Binary files /dev/null and b/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/components/lib/quartz-2.3.2.jar differ diff --git a/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/conf/financial-services.xml b/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/conf/financial-services.xml index f1f1a211..4177a2d0 100644 --- a/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/conf/financial-services.xml +++ b/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/conf/financial-services.xml @@ -82,4 +82,31 @@ 2000 1500 + + + org.wso2.financial.services.accelerator.event.notifications.service.DefaultEventNotificationGenerator + www.wso2.com + 5 + + org.wso2.financial.services.accelerator.event.notifications.service.handler.DefaultEventCreationServiceHandler + org.wso2.financial.services.accelerator.event.notifications.service.handler.DefaultEventPollingServiceHandler + org.wso2.financial.services.accelerator.event.notifications.service.handler.DefaultEventSubscriptionServiceHandler + + true + true + true + true + + + false + 0 0/1 0 ? * * * + 60 + 5 + 60 + EX + 600 + 20 + org.wso2.financial.services.accelerator.event.notifications.service.realtime.service.DefaultRealtimeEventNotificationRequestGenerator + + diff --git a/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/resources/conf/templates/repository/conf/financial-services.xml.j2 b/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/resources/conf/templates/repository/conf/financial-services.xml.j2 index a8761461..92ada121 100644 --- a/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/resources/conf/templates/repository/conf/financial-services.xml.j2 +++ b/financial-services-accelerator/accelerators/fs-is/carbon-home/repository/resources/conf/templates/repository/conf/financial-services.xml.j2 @@ -210,4 +210,102 @@ 1000 {% endif %} + + + {% if financial_services.event.notifications.event_notification_generator is defined %} + {{financial_services.event.notifications.event_notification_generator}} + {% else %} + org.wso2.financial.services.accelerator.event.notifications.service.DefaultEventNotificationGenerator + {% endif %} + {% if financial_services.event.notifications.token_issuer is defined %} + {{financial_services.event.notifications.token_issuer}} + {% else %} + www.wso2.com + {% endif %} + {% if financial_services.event.notifications.number_of_sets_to_return %} + {{financial_services.event.notifications.number_of_sets_to_return}} + {% else %} + 5 + {% endif %} + + {% if financial_services.event.notifications.event_creation_handler is defined %} + {{financial_services.event.notifications.event_creation_handler}} + {% else %} + org.wso2.financial.services.accelerator.event.notifications.service.handler.DefaultEventCreationServiceHandler + {% endif %} + {% if financial_services.event.notifications.event_polling_handler is defined %} + {{financial_services.event.notifications.event_polling_handler}} + {% else %} + org.wso2.financial.services.accelerator.event.notifications.service.handler.DefaultEventPollingServiceHandler + {% endif %} + {% if financial_services.event.notifications.event_subscription_handler is defined %} + {{financial_services.event.notifications.event_subscription_handler}} + {% else %} + org.wso2.financial.services.accelerator.event.notifications.service.handler.DefaultEventSubscriptionServiceHandler + {% endif %} + + {% if financial_services.event.notifications.set_sub_claim_included is defined%} + {{financial_services.event.notifications.set_sub_claim_included}} + {% else %} + true + {% endif %} + {% if financial_services.event.notifications.set_txn_claim_included is defined %} + {{financial_services.event.notifications.set_txn_claim_included}} + {% else %} + true + {% endif %} + {% if financial_services.event.notifications.set_toe_cliam_included is defined %} + {{financial_services.event.notifications.set_toe_cliam_included}} + {% else %} + true + {% endif %} + + + {% if financial_services.event.notifications.realtime.enable is defined %} + {{financial_services.event.notifications.realtime.enable}} + {% else %} + false + {% endif %} + {% if financial_services.event.notifications.realtime.periodic_cron_expression is defined %} + {{financial_services.event.notifications.realtime.periodic_cron_expression}} + {% else %} + 0 0/1 0 ? * * * + {% endif %} + {% if financial_services.event.notifications.realtime.request_timeout is defined %} + {{financial_services.event.notifications.realtime.request_timeout}} + {% else %} + 60 + {% endif %} + {% if financial_services.event.notifications.realtime.maximum_retry_count is defined %} + {{financial_services.event.notifications.realtime.maximum_retry_count}} + {% else %} + 5 + {% endif %} + {% if financial_services.event.notifications.realtime.initial_retry_waiting_time is defined %} + {{financial_services.event.notifications.realtime.initial_retry_waiting_time}} + {% else %} + 60 + {% endif %} + {% if financial_services.event.notifications.realtime.retry_function is defined %} + {{financial_services.event.notifications.realtime.retry_function}} + {% else %} + EX + {% endif %} + {% if financial_services.event.notifications.realtime.circuit_breaker_open_timeout is defined %} + {{financial_services.event.notifications.realtime.circuit_breaker_open_timeout}} + {% else %} + 600 + {% endif %} + {% if financial_services.event.notifications.realtime.thread_pool_size is defined %} + {{financial_services.event.notifications.realtime.thread_pool_size}} + {% else %} + 20 + {% endif %} + {% if financial_services.event.notifications.realtime.event_notification_request_generator is defined %} + {{financial_services.event.notifications.realtime.event_notification_request_generator}} + {% else %} + org.wso2.financial.services.accelerator.event.notifications.service.realtime.service.DefaultRealtimeEventNotificationRequestGenerator + {% endif %} + + diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/config/FinancialServicesConfigParser.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/config/FinancialServicesConfigParser.java index 0f3504f2..f6084dbd 100644 --- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/config/FinancialServicesConfigParser.java +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/config/FinancialServicesConfigParser.java @@ -601,4 +601,154 @@ public String getConsentValidationConfig() { return source.map(String::trim).orElse(""); } + //Event notifications configurations. + public String getEventNotificationTokenIssuer() { + + Optional source = getConfigurationFromKeyAsString(FinancialServicesConstants.TOKEN_ISSUER); + return source.map(String::trim).orElse("www.wso2.com"); + } + + public int getNumberOfSetsToReturn() { + + Optional config = getConfigurationFromKeyAsString(FinancialServicesConstants.MAX_SETS_TO_RETURN); + return config.map(Integer::parseInt).orElse(5); + } + + public boolean isSubClaimIncluded() { + + Optional config = getConfigurationFromKeyAsString(FinancialServicesConstants.IS_SUB_CLAIM_INCLUDED); + return config.map(Boolean::parseBoolean).orElse(false); + } + + public boolean isToeClaimIncluded() { + + Optional config = getConfigurationFromKeyAsString(FinancialServicesConstants.IS_TOE_CLAIM_INCLUDED); + return config.map(Boolean::parseBoolean).orElse(false); + } + + public boolean isTxnClaimIncluded() { + + Optional config = getConfigurationFromKeyAsString(FinancialServicesConstants.IS_TXN_CLAIM_INCLUDED); + return config.map(Boolean::parseBoolean).orElse(false); + } + + /** + * Method to determine real-time event notification feature is enabled or not from the configurations. + * + * @return boolean value indicating the state + */ + public boolean isRealtimeEventNotificationEnabled() { + + Optional config = getConfigurationFromKeyAsString( + FinancialServicesConstants.REALTIME_EVENT_NOTIFICATION_ENABLED); + return config.map(Boolean::parseBoolean).orElse(false); + } + + /** + * Method to get periodic Cron expression config for realtime event notifications scheduler. + * + * @return String Cron expression to trigger the Cron job for real-time event notification + */ + public String getRealtimeEventNotificationSchedulerCronExpression() { + + Optional source = getConfigurationFromKeyAsString(FinancialServicesConstants.PERIODIC_CRON_EXPRESSION); + return source.map(String::trim).orElse("0 0/1 0 ? * * *"); + } + + /** + * Method to get TIMEOUT_IN_SECONDS config for realtime event notifications. + * + * @return integer timeout for the HTTP Client's POST requests + */ + public int getRealtimeEventNotificationTimeoutInSeconds() { + + Optional config = getConfigurationFromKeyAsString(FinancialServicesConstants.TIMEOUT_IN_SECONDS); + return config.map(Integer::parseInt).orElse(60); + } + + /** + * Method to get MAX_RETRIES config for realtime event notifications. + * + * @return integer maximum number of retries to the retry policy in real-time notification sender + */ + public int getRealtimeEventNotificationMaxRetries() { + + Optional config = getConfigurationFromKeyAsString(FinancialServicesConstants.MAX_RETRIES); + return config.map(Integer::parseInt).orElse(5); + } + + /** + * Method to get INITIAL_BACKOFF_TIME_IN_SECONDS config for realtime event notifications. + * + * @return integer start waiting time for the retry policy before the first retry + */ + public int getRealtimeEventNotificationInitialBackoffTimeInSeconds() { + + Optional config = getConfigurationFromKeyAsString( + FinancialServicesConstants.INITIAL_BACKOFF_TIME_IN_SECONDS); + return config.map(Integer::parseInt).orElse(60); + } + + /** + * Method to get BACKOFF_FUNCTION config for realtime event notifications. + * Function name should be "EX", "CONSTANT" or "LINEAR". + * + * @return string indicating the retry function + */ + public String getRealtimeEventNotificationBackoffFunction() { + + Optional source = getConfigurationFromKeyAsString(FinancialServicesConstants.BACKOFF_FUNCTION); + return source.map(String::trim).orElse("EX"); + } + + /** + * Method to get CIRCUIT_BREAKER_OPEN_TIMEOUT_IN_SECONDS config for realtime event notifications. + * + * @return integer timeout to break the retrying process and make that notification as ERR + */ + public int getRealtimeEventNotificationCircuitBreakerOpenTimeoutInSeconds() { + + Optional config = getConfigurationFromKeyAsString( + FinancialServicesConstants.CIRCUIT_BREAKER_OPEN_TIMEOUT_IN_SECONDS); + return config.map(Integer::parseInt).orElse(600); + } + + /** + * Method to get EVENT_NOTIFICATION_THREAD_POOL_SIZE config for realtime event notifications. + * + * @return integer fix size to set the Thread Pool size in the real-time event notification sender + */ + public int getEventNotificationThreadPoolSize() { + + Optional config = getConfigurationFromKeyAsString( + FinancialServicesConstants.EVENT_NOTIFICATION_THREAD_POOL_SIZE); + return config.map(Integer::parseInt).orElse(20); + } + + /** + * Method to get EVENT_NOTIFICATION_GENERATOR config for event notifications. + * + * @return String class name of the event notification generator to generate the event notification payload + */ + public String getEventNotificationGenerator() { + + Optional source = getConfigurationFromKeyAsString( + FinancialServicesConstants.EVENT_NOTIFICATION_GENERATOR); + return source.map(String::trim).orElse("com.wso2.openbanking.accelerator.event.notifications." + + "service.service.DefaultEventNotificationGenerator"); + } + + /** + * Method to get REALTIME_EVENT_NOTIFICATION_REQUEST_GENERATOR config for realtime event notifications. + * + * @return String class path of the realtime event notification payload generator + */ + public String getRealtimeEventNotificationRequestGenerator() { + + Optional source = getConfigurationFromKeyAsString( + FinancialServicesConstants.REALTIME_EVENT_NOTIFICATION_REQUEST_GENERATOR); + return source.map(String::trim).orElse("com.wso2.openbanking.accelerator.event.notifications.service." + + "realtime.service.DefaultRealtimeEventNotificationRequestGenerator"); + } + } diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/constant/FinancialServicesConstants.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/constant/FinancialServicesConstants.java index cb33e13b..f2565dcc 100644 --- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/constant/FinancialServicesConstants.java +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/constant/FinancialServicesConstants.java @@ -91,5 +91,31 @@ public class FinancialServicesConstants { public static final String KEYSTORE_PASSWORD_TAG = "Security.InternalKeyStore.Password"; public static final String SIGNING_ALIAS_TAG = "Security.InternalKeyStore.KeyAlias"; public static final String SIGNING_KEY_PASSWORD = "Security.InternalKeyStore.KeyPassword"; + + //Event Notifications Constants + public static final String EVENT_NOTIFICATION_GENERATOR = "EventNotifications.NotificationGeneration." + + "NotificationGenerator"; + public static final String TOKEN_ISSUER = "EventNotifications.NotificationGeneration.TokenIssuer"; + public static final String MAX_SETS_TO_RETURN = "EventNotifications.NotificationGeneration.NumberOfSetsToReturn"; + public static final String SIGNING_ALIAS = "EventNotifications.SigningAlias"; + public static final String IS_SUB_CLAIM_INCLUDED = "EventNotifications.PollingResponseParams.IsSubClaimAvailable"; + public static final String IS_TXN_CLAIM_INCLUDED = "EventNotifications.PollingResponseParams.IsTxnClaimAvailable"; + public static final String IS_TOE_CLAIM_INCLUDED = "EventNotifications.PollingResponseParams.IsToeClaimAvailable"; + public static final String EVENT_CREATION_HANDLER = "EventNotifications.EventCreationHandler"; + public static final String EVENT_POLLING_HANDLER = "EventNotifications.EventPollingHandler"; + public static final String EVENT_SUBSCRIPTION_HANDLER = "EventNotifications.EventSubscriptionHandler"; + public static final String REALTIME_EVENT_NOTIFICATION_ENABLED = "EventNotifications.Realtime.Enable"; + public static final String PERIODIC_CRON_EXPRESSION = "EventNotifications.Realtime.PeriodicCronExpression"; + public static final String TIMEOUT_IN_SECONDS = "EventNotifications.Realtime.TimeoutInSeconds"; + public static final String MAX_RETRIES = "EventNotifications.Realtime.MaxRetries"; + public static final String INITIAL_BACKOFF_TIME_IN_SECONDS = + "EventNotifications.Realtime.InitialBackoffTimeInSeconds"; + public static final String BACKOFF_FUNCTION = "EventNotifications.Realtime.BackoffFunction"; + public static final String CIRCUIT_BREAKER_OPEN_TIMEOUT_IN_SECONDS = + "EventNotifications.Realtime.CircuitBreakerOpenTimeoutInSeconds"; + public static final String EVENT_NOTIFICATION_THREAD_POOL_SIZE = + "EventNotifications.Realtime.EventNotificationThreadPoolSize"; + public static final String REALTIME_EVENT_NOTIFICATION_REQUEST_GENERATOR = + "EventNotifications.Realtime.RequestGenerator"; } diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/util/HTTPClientUtils.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/util/HTTPClientUtils.java index e42ef2cc..633ea10c 100644 --- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/util/HTTPClientUtils.java +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/util/HTTPClientUtils.java @@ -88,6 +88,35 @@ public static CloseableHttpClient getHttpsClient() throws FinancialServicesExcep return HttpClients.custom().setConnectionManager(connectionManager).build(); } + /** + * Get closeable https client to send realtime event notifications. + * + * @return Closeable https client + * @throws FinancialServicesException FinancialServicesException exception + */ + @Generated(message = "Ignoring since method contains no logics") + public static CloseableHttpClient getRealtimeEventNotificationHttpsClient() throws FinancialServicesException { + + SSLConnectionSocketFactory sslsf = createSSLConnectionSocketFactory(); + + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(HTTP_PROTOCOL, new PlainConnectionSocketFactory()) + .register(HTTPS_PROTOCOL, sslsf) + .build(); + + final PoolingHttpClientConnectionManager connectionManager = (socketFactoryRegistry != null) ? + new PoolingHttpClientConnectionManager(socketFactoryRegistry) : + new PoolingHttpClientConnectionManager(); + + // configuring default maximum connections + connectionManager.setMaxTotal(FinancialServicesConfigParser.getInstance() + .getRealtimeEventNotificationMaxRetries() + 1); + connectionManager.setDefaultMaxPerRoute(FinancialServicesConfigParser.getInstance() + .getRealtimeEventNotificationMaxRetries() + 1); + + return HttpClients.custom().setConnectionManager(connectionManager).build(); + } + /** * create a SSL Connection Socket Factory. * diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/util/JWTUtils.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/util/JWTUtils.java index 3949f857..234fc03f 100644 --- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/util/JWTUtils.java +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/main/java/org/wso2/financial/services/accelerator/common/util/JWTUtils.java @@ -20,8 +20,11 @@ import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.JWSObject; +import com.nimbusds.jose.JWSSigner; import com.nimbusds.jose.JWSVerifier; +import com.nimbusds.jose.crypto.RSASSASigner; import com.nimbusds.jose.crypto.RSASSAVerifier; import com.nimbusds.jose.jwk.source.RemoteJWKSet; import com.nimbusds.jose.proc.BadJOSEException; @@ -31,6 +34,7 @@ import com.nimbusds.jose.proc.SimpleSecurityContext; import com.nimbusds.jose.util.DefaultResourceRetriever; import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.JWTParser; import com.nimbusds.jwt.SignedJWT; import com.nimbusds.jwt.proc.ConfigurableJWTProcessor; @@ -39,10 +43,12 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.core.util.KeyStoreManager; 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.exception.ConsentManagementException; import org.wso2.financial.services.accelerator.common.exception.FinancialServicesException; +import org.wso2.financial.services.accelerator.common.exception.FinancialServicesRuntimeException; import org.wso2.financial.services.accelerator.common.internal.FinancialServicesCommonDataHolder; import java.io.FileInputStream; @@ -50,6 +56,7 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.security.Key; import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; @@ -57,6 +64,7 @@ import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; @@ -197,6 +205,7 @@ public static boolean isValidJWSFormat(String jwsString) { * parsable JWT * */ + @Generated(message = "Excluding from code coverage as it require external call") public static SignedJWT getSignedJWT(String jwtString) throws ParseException { if (isValidJWSFormat(jwtString)) { @@ -353,4 +362,51 @@ public static KeyStore getTrustStore() throws ConsentManagementException { } return FinancialServicesCommonDataHolder.getInstance().getTrustStore(); } + + /** + * Sign a string body using the carbon default key pair. + * Skipped in unit tests since @KeystoreManager cannot be mocked + * + * @param body the body that needs to be signed as a string + * @return string value of the signed JWT + * @throws Exception error if the tenant is invalid + */ + public static String signJWTWithDefaultKey(String body) throws Exception { + KeyStoreManager keyStoreManager = KeyStoreManager.getInstance(-1234); + Key privateKey = keyStoreManager.getDefaultPrivateKey(); + return generateJWT(body, privateKey); + } + + /** + * Util method to generate JWT using a payload and a private key. RS256 is the + * algorithm used + * + * @param payload The payload body to be signed + * @param privateKey The private key for the JWT to be signed with + * @return String signed JWT + */ + @Generated(message = "Excluding from code coverage as it require external call") + public static String generateJWT(String payload, Key privateKey) { + + if (privateKey == null || payload == null) { + log.debug("Null value passed for payload or key. Cannot generate JWT"); + throw new FinancialServicesRuntimeException("Payload and key cannot be null"); + } + + if (!(privateKey instanceof RSAPrivateKey)) { + throw new FinancialServicesRuntimeException("Private key should be an instance of RSAPrivateKey"); + } + + JWSSigner signer = new RSASSASigner((RSAPrivateKey) privateKey); + JWSHeader.Builder headerBuilder = new JWSHeader.Builder(JWSAlgorithm.RS256); + + SignedJWT signedJWT = null; + try { + signedJWT = new SignedJWT(headerBuilder.build(), JWTClaimsSet.parse(payload)); + signedJWT.sign(signer); + } catch (ParseException | JOSEException e) { + throw new FinancialServicesRuntimeException("Error occurred while signing JWT"); + } + return signedJWT.serialize(); + } } diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/test/java/org/wso2/financial/services/accelerator/common/test/FSConfigParserTests.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/test/java/org/wso2/financial/services/accelerator/common/test/FSConfigParserTests.java index 1f4cc70d..007d5a5c 100644 --- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/test/java/org/wso2/financial/services/accelerator/common/test/FSConfigParserTests.java +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/test/java/org/wso2/financial/services/accelerator/common/test/FSConfigParserTests.java @@ -203,4 +203,103 @@ public void testGetConsentValidationConfig() { Assert.assertNotNull(FinancialServicesConfigParser.getInstance().getConsentValidationConfig()); } + + @Test(priority = 24) + public void testGetEventNotificationTokenIssuer() { + + Assert.assertNotNull(FinancialServicesConfigParser.getInstance().getEventNotificationTokenIssuer()); + } + + @Test(priority = 25) + public void testGetNumberOfSetsToReturn() { + + Assert.assertEquals(FinancialServicesConfigParser.getInstance().getNumberOfSetsToReturn(), 5); + } + + @Test(priority = 26) + public void testIsSubClaimIncluded() { + + Assert.assertFalse(FinancialServicesConfigParser.getInstance().isSubClaimIncluded()); + } + + @Test(priority = 27) + public void testIsToeClaimIncluded() { + + Assert.assertFalse(FinancialServicesConfigParser.getInstance().isToeClaimIncluded()); + } + + @Test(priority = 28) + public void testIsTxnClaimIncluded() { + + Assert.assertFalse(FinancialServicesConfigParser.getInstance().isTxnClaimIncluded()); + } + + @Test(priority = 29) + public void testIsRealtimeEventNotificationEnabled() { + + Assert.assertFalse(FinancialServicesConfigParser.getInstance().isRealtimeEventNotificationEnabled()); + } + + @Test(priority = 30) + public void testGetRealtimeEventNotificationSchedulerCronExpression() { + + Assert.assertNotNull(FinancialServicesConfigParser.getInstance() + .getRealtimeEventNotificationSchedulerCronExpression()); + } + + @Test(priority = 31) + public void testGetRealtimeEventNotificationTimeoutInSeconds() { + + Assert.assertEquals(FinancialServicesConfigParser.getInstance() + .getRealtimeEventNotificationTimeoutInSeconds(), 60); + } + + @Test(priority = 32) + public void testGetRealtimeEventNotificationMaxRetries() { + + Assert.assertEquals(FinancialServicesConfigParser.getInstance() + .getRealtimeEventNotificationMaxRetries(), 5); + } + + @Test(priority = 33) + public void testGetRealtimeEventNotificationInitialBackoffTimeInSeconds() { + + Assert.assertEquals(FinancialServicesConfigParser.getInstance() + .getRealtimeEventNotificationInitialBackoffTimeInSeconds(), 60); + } + + @Test(priority = 34) + public void testGetRealtimeEventNotificationBackoffFunction() { + + Assert.assertNotNull(FinancialServicesConfigParser.getInstance() + .getRealtimeEventNotificationBackoffFunction()); + } + + @Test(priority = 35) + public void testGetRealtimeEventNotificationCircuitBreakerOpenTimeoutInSeconds() { + + Assert.assertEquals(FinancialServicesConfigParser.getInstance() + .getRealtimeEventNotificationCircuitBreakerOpenTimeoutInSeconds(), 600); + } + @Test(priority = 36) + public void testGetEventNotificationThreadPoolSize() { + + Assert.assertEquals(FinancialServicesConfigParser.getInstance() + .getEventNotificationThreadPoolSize(), 20); + } + + @Test(priority = 37) + public void testGetEventNotificationGenerator() { + + Assert.assertNotNull(FinancialServicesConfigParser.getInstance() + .getEventNotificationGenerator()); + } + + @Test(priority = 38) + public void testGetRealtimeEventNotificationRequestGenerator() { + + Assert.assertNotNull(FinancialServicesConfigParser.getInstance() + .getRealtimeEventNotificationRequestGenerator()); + } + } diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/test/resources/repository/conf/financial-services.xml b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/test/resources/repository/conf/financial-services.xml index 9cb2eeb4..62336ba7 100644 --- a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/test/resources/repository/conf/financial-services.xml +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.common/src/test/resources/repository/conf/financial-services.xml @@ -160,69 +160,30 @@ - - www.wso2.com - 5 + + + org.wso2.financial.services.accelerator.event.notifications.service.DefaultEventNotificationGenerator + www.wso2.com + 5 + org.wso2.financial.services.accelerator.event.notifications.service.handler.DefaultEventCreationServiceHandler org.wso2.financial.services.accelerator.event.notifications.service.handler.DefaultEventPollingServiceHandler - org.wso2.financial.services.accelerator.event.notifications.service.service.DefaultEventNotificationGenerator org.wso2.financial.services.accelerator.event.notifications.service.handler.DefaultEventSubscriptionServiceHandler - true - true - true + false + false + false - - - - - false - - PS256 - ES256 - - - + false - - PS256 - ES256 - - - - - - - wso2carbon - wso2carbon-sandbox - 1234 - 5678 - - - 51200 - 2000 - 2000 - - - - - - - - - - - - - - true - 0 0/1 0 ? * * * - 60 - 5 - 60 - EX - 600 - 20 - org.wso2.financial.services.accelerator.event.notifications.service.realtime.service.DefaultRealtimeEventNotificationRequestGenerator - + 0 0/1 0 ? * * * + 60 + 5 + 60 + EX + 600 + 20 + org.wso2.financial.services.accelerator.event.notifications.service.realtime.service.DefaultRealtimeEventNotificationRequestGenerator + + diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/pom.xml b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/pom.xml new file mode 100644 index 00000000..4c3f4f99 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/pom.xml @@ -0,0 +1,222 @@ + + + 4.0.0 + + + financial-services-accelerator + org.wso2.financial.services.accelerator + 4.0.0-SNAPSHOT + ../../pom.xml + + + org.wso2.financial.services.accelerator.event.notifications.service + bundle + WSO2 Financial Services - Event Notification Service Module + + + + org.apache.commons + commons-lang3 + provided + + + org.json.wso2 + json + + + com.fasterxml.jackson.core + jackson-annotations + + + org.quartz-scheduler + quartz + + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.common + + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.consent.mgt.service + + + org.wso2.financial.services.accelerator + org.wso2.financial.services.accelerator.consent.mgt.dao + + + org.testng + testng + test + + + org.mockito + mockito-core + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + org.apache.felix + maven-bundle-plugin + true + + + + ${project.artifactId} + + + org.wso2.financial.services.accelerator.event.notifications.service.internal + + + org.osgi.framework;version="${osgi.framework.imp.pkg.version.range}", + org.osgi.service.component;version="${osgi.service.component.imp.pkg.version.range}", + org.apache.commons.lang3;version="${commons-lang3.version}", + org.apache.commons.logging;version="${commons.logging.version}", + org.json;version="${org.json.version}", + com.fasterxml.jackson.annotation;version="${jackson.databinding.version}", + com.fasterxml.jackson.databind;version="${jackson.databinding.version}", + com.nimbusds.jose;version="${org.wso2.orbit.nimbus.version.range}", + org.wso2.carbon.identity.application.common.*;version="${carbon.identity.framework.version.range}", + org.wso2.carbon.identity.oauth2.*;version="${identity.inbound.auth.oauth.version.range}", + org.wso2.financial.services.accelerator.common.*;version="${project.version}", + org.wso2.financial.services.accelerator.consent.mgt.dao.*;version="${project.version}", + org.wso2.financial.services.accelerator.consent.mgt.service.*;version="${project.version}", + + + !org.wso2.financial.services.accelerator.event.notifications.service.internal, + org.wso2.financial.services.accelerator.event.notifications.service.*;version="${project.version}", + + + javax.ws.rs-api;scope=compile;inline=false, + + <_dsannotations>* + + + + + + diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/DefaultEventNotificationGenerator.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/DefaultEventNotificationGenerator.java new file mode 100644 index 00000000..4ec4c6d4 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/DefaultEventNotificationGenerator.java @@ -0,0 +1,83 @@ +/** + * 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.service; + +import com.fasterxml.jackson.databind.JsonNode; +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.util.Generated; +import org.wso2.financial.services.accelerator.common.util.JWTUtils; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.Notification; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationEvent; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationResponse; + +import java.time.Instant; +import java.util.List; +import java.util.UUID; + +/** + * Default Event Notification Response Generator Class. + */ +public class DefaultEventNotificationGenerator implements EventNotificationGenerator { + + private static Log log = LogFactory.getLog(DefaultEventNotificationGenerator.class); + + @Override + public NotificationResponse generateEventNotificationBody(Notification notification, + List notificationEventList) + throws FSEventNotificationException { + + NotificationResponse notificationResponse = new NotificationResponse(); + //get current time in milliseconds + Long currentTime = Instant.now().getEpochSecond(); + + //generate transaction Identifier + String transactionIdentifier = UUID.randomUUID().toString(); + + notificationResponse.setIss(FinancialServicesConfigParser.getInstance().getEventNotificationTokenIssuer()); + notificationResponse.setIat(currentTime); + notificationResponse.setAud(notification.getClientId()); + notificationResponse.setJti(notification.getNotificationId()); + notificationResponse.setTxn(transactionIdentifier); + notificationResponse.setToe(notification.getUpdatedTimeStamp()); + notificationResponse.setSub(generateSubClaim(notification)); + notificationResponse.setEvents(notificationEventList); + return notificationResponse; + } + + @Generated(message = "Excluded from tests as using a util method from a different package") + public String generateEventNotification(JsonNode jsonNode) throws FSEventNotificationException { + + try { + return JWTUtils.signJWTWithDefaultKey(jsonNode.toString()); + } catch (Exception e) { + log.error("Error while signing the JWT token", e); + throw new FSEventNotificationException("Error while signing the JWT token", e); + } + + } + + @Generated(message = "Private method tested when the used method is tested") + private String generateSubClaim(Notification notification) { + return notification.getClientId(); + } + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventCreationService.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventCreationService.java new file mode 100644 index 00000000..acefc46a --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventCreationService.java @@ -0,0 +1,117 @@ +/** + * 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.service; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONObject; +import org.wso2.financial.services.accelerator.common.util.DatabaseUtils; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.dao.EventNotificationDAO; +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.model.Notification; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationEvent; +import org.wso2.financial.services.accelerator.event.notifications.service.persistence.EventNotificationStoreInitializer; + +import java.sql.Connection; +import java.util.ArrayList; +import java.util.Map; +import java.util.UUID; + +/** + * This is the event creation service class. + */ +public class EventCreationService { + + private static Log log = LogFactory.getLog(EventCreationService.class); + + /** + * The publishEventNotification methods will call the dao layer to persist the event + * notifications for event polling request. + * + * @param notificationCreationDTO Notification creation DTO + * @return Event Response + * @throws FSEventNotificationException Exception when persisting event notification data + */ + public String publishEventNotification(NotificationCreationDTO notificationCreationDTO) + throws FSEventNotificationException { + + Connection connection = DatabaseUtils.getDBConnection(); + Notification notification = getNotification(notificationCreationDTO); + ArrayList eventsList = getEvents(notificationCreationDTO.getEventPayload()); + + EventNotificationDAO eventCreationDAO = EventNotificationStoreInitializer.getEventNotificationDAO(); + String eventResponse = null; + + try { + eventResponse = eventCreationDAO.persistEventNotification(connection, notification, eventsList); + DatabaseUtils.commitTransaction(connection); + + //TODO: + // Check whether the real time event notification is enabled. +// if (FinancialServicesConfigParser.getInstance().isRealtimeEventNotificationEnabled()) { +// new Thread(new EventNotificationProducerService(notification, eventsList)).start(); +// } + return eventResponse; + } catch (FSEventNotificationException e) { + DatabaseUtils.rollbackTransaction(connection); + throw new FSEventNotificationException("Error when persisting event notification data", e); + } finally { + log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); + DatabaseUtils.closeConnection(connection); + } + } + + /** + * The getEvents method is used to get the NotificationEvents Array list from payload. + * + * @param notificationEvents Notification Events to convert + * @return Event notification List + */ + private ArrayList getEvents(Map notificationEvents) { + + ArrayList eventsList = new ArrayList<>(); + for (Map.Entry entry : notificationEvents.entrySet()) { + NotificationEvent notificationEvent = new NotificationEvent(); + notificationEvent.setEventType(entry.getKey()); + notificationEvent.setEventInformation(entry.getValue()); + eventsList.add(notificationEvent); + } + + return eventsList; + } + + /** + * The getNotification method is used to get the NotificationDAO from payload. + * + * @param notificationCreationDTO Notification Creation DTO + * @return Notification Details + */ + private Notification getNotification(NotificationCreationDTO notificationCreationDTO) { + + Notification notification = new Notification(); + notification.setNotificationId(UUID.randomUUID().toString()); + notification.setClientId(notificationCreationDTO.getClientId()); + notification.setResourceId(notificationCreationDTO.getResourceId()); + notification.setStatus(EventNotificationConstants.OPEN); + + return notification; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventNotificationGenerator.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventNotificationGenerator.java new file mode 100644 index 00000000..6cde9dd3 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventNotificationGenerator.java @@ -0,0 +1,48 @@ +/** + * 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.service; + +import com.fasterxml.jackson.databind.JsonNode; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.Notification; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationEvent; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationResponse; + +import java.util.List; + +/** + * Interface for event notification generation. For custom class extensions the class name + * is to be referred from the event_notification_generator in deployment.toml + */ +public interface EventNotificationGenerator { + + /** + * This method is to generate event notification body. To generate custom values + * for the body this method should be extended. + * + * @param notification Notification details + * @param notificationEventList List of notification events + * @return Event Notification Response Body + * @throws FSEventNotificationException Exception when generating event notification body + */ + NotificationResponse generateEventNotificationBody(Notification notification, List + notificationEventList) throws FSEventNotificationException; + + String generateEventNotification(JsonNode jsonNode) throws FSEventNotificationException; +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventPollingService.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventPollingService.java new file mode 100644 index 00000000..e2513844 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventPollingService.java @@ -0,0 +1,161 @@ +/** + * 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.service; + +import com.nimbusds.jose.JOSEException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.financial.services.accelerator.common.util.DatabaseUtils; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.dao.EventNotificationDAO; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.AggregatedPollingResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventPolling; +import org.wso2.financial.services.accelerator.event.notifications.service.model.Notification; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationError; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationEvent; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.persistence.EventNotificationStoreInitializer; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +import java.io.IOException; +import java.sql.Connection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This is the event polling service. + */ +public class EventPollingService { + + private static Log log = LogFactory.getLog(EventPollingService.class); + + /** + * The pollEvents methods will return the Aggregated Polling Response for + * event polling request. + * @param eventPolling Event polling request + * @return AggregatedPollingResponse Aggregated Polling Response + * @throws FSEventNotificationException Exception when polling events + */ + public AggregatedPollingResponse pollEvents(EventPolling eventPolling) + throws FSEventNotificationException { + + Connection connection = DatabaseUtils.getDBConnection(); + AggregatedPollingResponse aggregatedPollingResponse = new AggregatedPollingResponse(); + EventNotificationDAO eventNotificationDAO = EventNotificationStoreInitializer.getEventNotificationDAO(); + + EventNotificationGenerator eventNotificationGenerator = EventNotificationServiceUtil. + getEventNotificationGenerator(); + + Map sets = new HashMap<>(); + + //Short polling + if (eventPolling.getReturnImmediately()) { + + try { + //Update notifications with ack + for (String notificationId : eventPolling.getAck()) { + eventNotificationDAO.updateNotificationStatusById(connection, notificationId, + EventNotificationConstants.ACK); + } + + //Update notifications with err + for (Map.Entry entry: eventPolling.getErrors().entrySet()) { + //Check if the notification is in OPEN status + if (eventNotificationDAO.getNotificationStatus(connection, entry.getKey())) { + eventNotificationDAO.updateNotificationStatusById(connection, entry.getKey(), + EventNotificationConstants.ERROR); + eventNotificationDAO.storeErrorNotification(connection, entry.getValue()); + } + } + + //Retrieve notifications + int maxEvents = eventPolling.getMaxEvents(); + + if (maxEvents == 0) { + aggregatedPollingResponse.setSets(sets); + aggregatedPollingResponse.setStatus(EventNotificationConstants.OK); + } else { + + int setsToReturn = eventPolling.getSetsToReturn(); + + List notificationList; + + if (maxEvents < setsToReturn) { + notificationList = eventNotificationDAO.getNotificationsByClientIdAndStatus(connection, + eventPolling.getClientId(), EventNotificationConstants.OPEN, maxEvents); + + } else { + notificationList = eventNotificationDAO.getNotificationsByClientIdAndStatus(connection, + eventPolling.getClientId(), EventNotificationConstants.OPEN, setsToReturn); + } + + if (notificationList.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug(String.format("No FS Event Notifications available for for the client " + + "with ID : '%s'.", eventPolling.getClientId().replaceAll("[\r\n]", ""))); + } + aggregatedPollingResponse.setStatus(EventNotificationConstants.NOT_FOUND); + } else { + if (log.isDebugEnabled()) { + log.debug(String.format("FS Event Notifications available for the client " + + "with ID : '%s'.", eventPolling.getClientId().replaceAll("[\r\n]", ""))); + } + aggregatedPollingResponse.setStatus(EventNotificationConstants.OK); + + for (Notification notification : notificationList) { + + //Get events by notificationId + List notificationEvents = eventNotificationDAO. + getEventsByNotificationID(connection, notification.getNotificationId()); + + NotificationResponse responseNotification = eventNotificationGenerator. + generateEventNotificationBody(notification, notificationEvents); + sets.put(notification.getNotificationId(), eventNotificationGenerator + .generateEventNotification(NotificationResponse.getJsonNode(responseNotification))); + log.info("Retrieved FS event notifications"); + } + aggregatedPollingResponse.setSets(sets); + } + } + + int count = eventNotificationDAO.getNotificationCountByClientIdAndStatus(connection, + eventPolling.getClientId(), EventNotificationConstants.OPEN) + - aggregatedPollingResponse.getSets().size(); + + aggregatedPollingResponse.setCount(count); + DatabaseUtils.commitTransaction(connection); + + return aggregatedPollingResponse; + } catch (FSEventNotificationException | + IOException | JOSEException | IdentityOAuth2Exception e) { + log.debug("Error when retrieving FS event notifications.", e); + DatabaseUtils.rollbackTransaction(connection); + throw new FSEventNotificationException("Error when retrieving FS event notifications.", e); + } finally { + log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); + DatabaseUtils.closeConnection(connection); + } + } + + return null; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventSubscriptionService.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventSubscriptionService.java new file mode 100644 index 00000000..0c7db316 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/EventSubscriptionService.java @@ -0,0 +1,266 @@ +/** + * 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.service; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONException; +import org.json.JSONObject; +import org.wso2.financial.services.accelerator.common.util.DatabaseUtils; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.dao.EventSubscriptionDAO; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventSubscription; +import org.wso2.financial.services.accelerator.event.notifications.service.persistence.EventNotificationStoreInitializer; + +import java.sql.Connection; +import java.util.List; + +/** + * This is the event subscription service class. + */ +public class EventSubscriptionService { + private static final Log log = LogFactory.getLog(EventSubscriptionService.class); + + /** + * This method will call the dao layer to persist the event subscription. + * + * @param eventSubscription event subscription object that needs to be persisted + * @return event subscription object that is persisted + * @throws FSEventNotificationException if an error occurred while persisting the event subscription + */ + public EventSubscription createEventSubscription(EventSubscription eventSubscription) + throws FSEventNotificationException { + + EventSubscriptionDAO eventSubscriptionDAO = EventNotificationStoreInitializer.getEventSubscriptionDAO(); + + Connection connection = DatabaseUtils.getDBConnection(); + + try { + //store event subscription data in the database + EventSubscription storeEventSubscriptionResult = eventSubscriptionDAO. + storeEventSubscription(connection, eventSubscription); + //store subscribed event types in the database + if (eventSubscription.getEventTypes() != null && !eventSubscription.getEventTypes().isEmpty()) { + List storedEventTypes = eventSubscriptionDAO.storeSubscribedEventTypes(connection, + storeEventSubscriptionResult.getSubscriptionId(), eventSubscription.getEventTypes()); + storeEventSubscriptionResult.setEventTypes(storedEventTypes); + } + log.debug("Event subscription created successfully."); + DatabaseUtils.commitTransaction(connection); + return storeEventSubscriptionResult; + } catch (FSEventNotificationException e) { + log.error("Error while creating event subscription.", e); + DatabaseUtils.rollbackTransaction(connection); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_STORING_EVENT_SUBSCRIPTION, e); + } finally { + log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); + DatabaseUtils.closeConnection(connection); + } + } + + /** + * This method will call the dao layer to retrieve a single event subscription. + * + * @param subscriptionId subscription id of the event subscription + * @return event subscription object that is retrieved + * @throws FSEventNotificationException if an error occurred while retrieving the event subscription + */ + public EventSubscription getEventSubscriptionBySubscriptionId(String subscriptionId) + throws FSEventNotificationException { + + EventSubscriptionDAO eventSubscriptionDAO = EventNotificationStoreInitializer.getEventSubscriptionDAO(); + + Connection connection = DatabaseUtils.getDBConnection(); + + try { + EventSubscription eventSubscription = eventSubscriptionDAO + .getEventSubscriptionBySubscriptionId(connection, subscriptionId); + if (log.isDebugEnabled()) { + log.debug(String.format("Event subscription for subscription Id %s retrieved successfully.", + subscriptionId.replaceAll("[\r\n]", ""))); + } + DatabaseUtils.commitTransaction(connection); + return eventSubscription; + } catch (FSEventNotificationException e) { + log.error("Error while retrieving event subscription.", e); + DatabaseUtils.rollbackTransaction(connection); + throw new FSEventNotificationException(e.getMessage(), e); + } finally { + log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); + DatabaseUtils.closeConnection(connection); + } + } + + /** + * This method will call the dao layer to retrieve all event subscriptions of a client. + * + * @param clientId client id of the event subscription + * @return list of event subscriptions that are retrieved + * @throws FSEventNotificationException if an error occurred while retrieving the event subscriptions + */ + public List getEventSubscriptionsByClientId(String clientId) + throws FSEventNotificationException { + + Connection connection = DatabaseUtils.getDBConnection(); + try { + EventSubscriptionDAO eventSubscriptionDAO = EventNotificationStoreInitializer.getEventSubscriptionDAO(); + List eventSubscriptions = eventSubscriptionDAO + .getEventSubscriptionsByClientId(connection, clientId); + if (log.isDebugEnabled()) { + log.debug(String.format("Event subscriptions for client Id %s retrieved successfully.", + clientId.replaceAll("[\r\n]", ""))); + } + DatabaseUtils.commitTransaction(connection); + return eventSubscriptions; + } catch (FSEventNotificationException e) { + log.error("Error while retrieving event subscriptions.", e); + DatabaseUtils.rollbackTransaction(connection); + throw new FSEventNotificationException(e.getMessage(), e); + } finally { + log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); + DatabaseUtils.closeConnection(connection); + } + } + + /** + * This method will call the dao layer to retrieve all event subscriptions by event type. + * + * @param eventType event type that needs to be subscribed by the retrieving event subscriptions. + * @return list of event subscriptions that are retrieved + * @throws FSEventNotificationException if an error occurred while retrieving the event subscriptions + */ + public List getEventSubscriptionsByEventType(String eventType) + throws FSEventNotificationException { + + + Connection connection = DatabaseUtils.getDBConnection(); + try { + EventSubscriptionDAO eventSubscriptionDAO = EventNotificationStoreInitializer.getEventSubscriptionDAO(); + List eventSubscriptions = eventSubscriptionDAO + .getEventSubscriptionsByEventType(connection, eventType); + if (log.isDebugEnabled()) { + log.debug(String.format("Event subscriptions for event type %s retrieved successfully.", + eventType.replaceAll("[\r\n]", ""))); + } + DatabaseUtils.commitTransaction(connection); + return eventSubscriptions; + } catch (FSEventNotificationException e) { + log.error("Error while retrieving event subscriptions.", e); + DatabaseUtils.rollbackTransaction(connection); + throw new FSEventNotificationException(e.getMessage(), e); + } finally { + log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); + DatabaseUtils.closeConnection(connection); + } + } + + /** + * This method will call the dao layer to update an event subscription. + * + * @param eventSubscription event subscription object that needs to be updated + * @return true if the event subscription is updated successfully + * @throws FSEventNotificationException if an error occurred while updating the event subscription + */ + public Boolean updateEventSubscription(EventSubscription eventSubscription) + throws FSEventNotificationException { + + Connection connection = DatabaseUtils.getDBConnection(); + + EventSubscriptionDAO eventSubscriptionDAO = EventNotificationStoreInitializer.getEventSubscriptionDAO(); + + try { + //get the stored event subscription + EventSubscription retrievedEventSubscription = eventSubscriptionDAO. + getEventSubscriptionBySubscriptionId(connection, eventSubscription.getSubscriptionId()); + + //update request data column + JSONObject storedRequestData = new JSONObject(retrievedEventSubscription.getRequestData()); + JSONObject receivedRequestData = new JSONObject(eventSubscription.getRequestData()); + for (String key : storedRequestData.keySet()) { + if (receivedRequestData.has(key)) { + storedRequestData.put(key, receivedRequestData.get(key)); + } + } + eventSubscription.setRequestData(storedRequestData.toString()); + + //update event subscription + boolean isUpdated = eventSubscriptionDAO.updateEventSubscription(connection, eventSubscription); + + //update subscribed event types + if (isUpdated && eventSubscription.getEventTypes() != null && + !eventSubscription.getEventTypes().isEmpty()) { + //delete the existing subscribed event types + eventSubscriptionDAO.deleteSubscribedEventTypes(connection, eventSubscription.getSubscriptionId()); + //store the updated subscribed event types + List storedEventTypes = eventSubscriptionDAO.storeSubscribedEventTypes(connection, + eventSubscription.getSubscriptionId(), eventSubscription.getEventTypes()); + eventSubscription.setEventTypes(storedEventTypes); + } else if (!isUpdated) { + log.debug("Event subscription update failed."); + DatabaseUtils.rollbackTransaction(connection); + } + log.debug("Event subscription updated successfully."); + DatabaseUtils.commitTransaction(connection); + return isUpdated; + } catch (JSONException e) { + log.error("Error while Parsing the stored request Object", e); + throw new FSEventNotificationException("Error while Parsing the stored request Object", e); + } catch (FSEventNotificationException e) { + log.error("Error while updating event subscription.", e); + DatabaseUtils.rollbackTransaction(connection); + throw new FSEventNotificationException(e.getMessage(), e); + } finally { + log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); + DatabaseUtils.closeConnection(connection); + } + } + + /** + * This method will call the dao layer to delete an event subscription. + * + * @param subscriptionId subscription id of the event subscription + * @return true if the event subscription is deleted successfully + * @throws FSEventNotificationException if an error occurred while deleting the event subscription + */ + public Boolean deleteEventSubscription(String subscriptionId) throws FSEventNotificationException { + + Connection connection = DatabaseUtils.getDBConnection(); + + try { + EventSubscriptionDAO eventSubscriptionDAO = EventNotificationStoreInitializer.getEventSubscriptionDAO(); + boolean isDeleted = eventSubscriptionDAO.deleteEventSubscription(connection, subscriptionId); + if (isDeleted) { + log.debug("Event subscription deleted successfully."); + DatabaseUtils.commitTransaction(connection); + } else { + log.debug("Event subscription deletion failed."); + DatabaseUtils.rollbackTransaction(connection); + } + return isDeleted; + } catch (FSEventNotificationException e) { + log.error("Error while deleting event subscription.", e); + DatabaseUtils.rollbackTransaction(connection); + throw new FSEventNotificationException(e.getMessage(), e); + } finally { + log.debug(EventNotificationConstants.DATABASE_CONNECTION_CLOSE_LOG_MSG); + DatabaseUtils.closeConnection(connection); + } + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/constants/EventNotificationConstants.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/constants/EventNotificationConstants.java new file mode 100644 index 00000000..78943682 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/constants/EventNotificationConstants.java @@ -0,0 +1,121 @@ +/** + * 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.service.constants; + +/** + * Event Notification Constants. + */ +public class EventNotificationConstants { + + //Service level constants + public static final String X_WSO2_CLIENT_ID = "x-wso2-client-id"; + + //Event Notification Status + public static final String ACK = "ACK"; + public static final String ERROR = "ERR"; + public static final String OPEN = "OPEN"; + + //Response Status + public static final String NOT_FOUND = "NOTFOUND"; + public static final String OK = "OK"; + public static final String CREATED = "CREATED"; + public static final String BAD_REQUEST = "BADREQUEST"; + public static final String NO_CONTENT = "NO_CONTENT"; + public static final String INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"; + //Database columns + public static final String NOTIFICATION_ID = "NOTIFICATION_ID"; + public static final String CLIENT_ID = "CLIENT_ID"; + public static final String RESOURCE_ID = "RESOURCE_ID"; + public static final String STATUS = "STATUS"; + public static final String UPDATED_TIMESTAMP = "UPDATED_TIMESTAMP"; + public static final String EVENT_INFO = "EVENT_INFO"; + public static final String EVENT_TYPE = "EVENT_TYPE"; + public static final String SUBSCRIPTION_ID = "SUBSCRIPTION_ID"; + public static final String CALLBACK_URL = "CALLBACK_URL"; + public static final String TIME_STAMP = "TIMESTAMP"; + public static final String SPEC_VERSION = "SPEC_VERSION"; + public static final String REQUEST = "REQUEST"; + + //Error Constants + public static final String ERROR_FIELD = "error"; + public static final String ERROR_DESCRIPTION_FIELD = "error_description"; + public static final String INVALID_REQUEST = "invalid_request"; + public static final String EVENT_NOTIFICATION_CREATION_ERROR = "Error occurred while saving event " + + "notifications in the database"; + public static final String MISSING_REQ_PAYLOAD = "No request payload found"; + public static final String MISSING_HEADER_PARAM_CLIENT_ID = "Missing header x-wso2-client-id"; + public static final String MISSING_HEADER_PARAM_RESOURCE_ID = "Missing header x-wso2-resource-id"; + public static final String ERROR_IN_EVENT_POLLING_REQUEST = "Error in event polling request"; + public static final String INVALID_CHARS_IN_HEADER_ERROR = "Invalid characters found in the request headers"; + + //Polling request params + public static final String SET_ERRORS = "setErrs"; + public static final String MAX_EVENTS = "maxEvents"; + public static final String DESCRIPTION = "description"; + public static final String RETURN_IMMEDIATELY = "returnImmediately"; + + //Polling response params + public static final String SETS = "sets"; + public static final String MORE_AVAILABLE = "moreAvailable"; + public static final String NOTIFICATIONS_ID = "notificationsID"; + + // Event Subscription Request Params + public static final String SUBSCRIPTION_ID_PARAM = "subscriptionId"; + public static final String CALLBACK_URL_PARAM = "callbackUrl"; + public static final String VERSION_PARAM = "version"; + public static final String EVENT_TYPES_PARAM = "eventTypes"; + public static final String EVENT_TYPE_PARAM = "eventType"; + public static final String DATA_PARAM = "data"; + + public static final String DB_ERROR_UPDATING = "Database error while updating notification with ID : " + + "'%s' in the database. "; + public static final String DB_ERROR_NOTIFICATION_RETRIEVE = "Error occurred while retrieving" + + " notifications for client ID : '%s'."; + public static final String DB_FAILED_ERROR_NOTIFICATION_STORING = "Failed to store error notification with ID : "; + public static final String DB_ERROR_STORING_ERROR_NOTIFICATION = "Error occurred while closing the " + + "event-notification database connection"; + public static final String DB_ERROR_EVENTS_RETRIEVE = "Error occurred while retrieving events for" + + " notifications ID : '%s'."; + public static final String PARSE_ERROR_NOTIFICATION_ID = "Error occurred while parsing events for" + + " notifications ID : '%s'."; + public static final String DB_CONN_ESTABLISHED = "Database connection is established to get notification " + + "for client ID : '%s' in the database. "; + public static final String RETRIEVED_NOTIFICATION_CLIENT = "Retrieved notification for client ID: '%s'. "; + + public static final String RETRIEVED_EVENTS_NOTIFICATION = "Retrieved events for notification ID: '%s'. "; + public static final String NO_NOTIFICATIONS_FOUND_CLIENT = "No notifications found for client ID - '%s'"; + public static final String NO_EVENTS_NOTIFICATION_ID = "No events found for notification ID - '%s'"; + public static final String INVALID_CLIENT_ID = "Invalid mandatory parameter x-wso2-client-id."; + public static final String DATABASE_CONNECTION_CLOSE_LOG_MSG = "Closing database connection"; + + public static final String ERROR_STORING_EVENT_SUBSCRIPTION = "Error occurred while storing event " + + "subscription in the database. "; + public static final String ERROR_UPDATING_EVENT_SUBSCRIPTION = "Error occurred while updating event " + + "subscription in the database. "; + public static final String ERROR_RETRIEVING_EVENT_SUBSCRIPTION = "Error occurred while retrieving event " + + "subscription in the database. "; + public static final String ERROR_RETRIEVING_EVENT_SUBSCRIPTIONS = "Error occurred while retrieving event " + + "subscriptions in the database."; + public static final String ERROR_DELETING_EVENT_SUBSCRIPTION = "Error occurred while deleting event " + + "subscription in the database. "; + public static final String EVENT_SUBSCRIPTION_NOT_FOUND = "Event subscription not found."; + public static final String EVENT_SUBSCRIPTIONS_NOT_FOUND = "Event subscriptions not found for the given client id."; + public static final String ERROR_HANDLING_EVENT_SUBSCRIPTION = "Error occurred while handling the event " + + "subscription request"; +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventNotificationDAO.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventNotificationDAO.java new file mode 100644 index 00000000..d195a96d --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventNotificationDAO.java @@ -0,0 +1,127 @@ +/** + * 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.service.dao; + +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.Notification; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationError; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationEvent; + +import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; + +/** + * Event Publisher DAO interface. + */ +public interface EventNotificationDAO { + + /** + * This method is used to persist event notifications in the database. + * + * @param connection Database connection + * @param notification Notification details + * @param eventsList List of notification events + * @return NotificationID of the saved notification. + * @throws FSEventNotificationException Exception when persisting event notification data + */ + String persistEventNotification(Connection connection, Notification notification, + ArrayList eventsList) + throws FSEventNotificationException; + + /** + * This method is to update the notification status by ID, allowed values are. + * OPEN,ACK and ERR + * + * @param connection Database connection + * @param notificationId Notification ID to update + * @param notificationStatus Notification status to update + * @throws FSEventNotificationException Exception when updating notification status by ID + */ + void updateNotificationStatusById(Connection connection, String notificationId, String notificationStatus) + throws FSEventNotificationException; + + /** + * This method is to store event notifications error details in the FS_NOTIFICATION table. + * + * @param connection Database connection + * @param notificationError Notification error details + * @throws FSEventNotificationException Exception when storing event notifications error details + */ + void storeErrorNotification(Connection connection, NotificationError notificationError) + throws FSEventNotificationException; + + /** + * This method is to retrieve given number of notifications in the FS_NOTIFICATION table by client and status. + * + * @param connection Database connection + * @param clientId Client ID to retrieve notifications + * @param status Notification status to retrieve + * @param max Maximum number of notifications to retrieve + * @return List of notifications by client and status + * @throws FSEventNotificationException Exception when retrieving notifications by client ID and status + */ + List getNotificationsByClientIdAndStatus(Connection connection, String clientId, String + status, int max) throws FSEventNotificationException; + + /** + * This method is to retrieve notifications by NotificationID. + * + * @param connection Database connection + * @param notificationId Notification ID to retrieve + * @return List of notifications by notification ID + * @throws FSEventNotificationException Exception when retrieving notifications by notification ID + */ + List getEventsByNotificationID(Connection connection, String notificationId) + throws FSEventNotificationException; + + /** + * This method is to retrieve notifications in the FS_NOTIFICATION table by status. + * + * @param connection Database connection + * @param status Notification status to retrieve + * @return List of notifications by status + * @throws FSEventNotificationException Exception when retrieving notifications by status + */ + List getNotificationsByStatus(Connection connection, String status) + throws FSEventNotificationException; + + /** + * This method is to retrieve notificationsCount by ClientId and Status. + * + * @param connection Database connection + * @param clientId Client ID to retrieve notifications + * @param eventStatus Notification status to retrieve + * @return Notification count by client ID and status + * @throws FSEventNotificationException Exception when retrieving notification count by client ID and status + */ + int getNotificationCountByClientIdAndStatus(Connection connection, String clientId, String eventStatus) + throws FSEventNotificationException; + + /** + * This method is to retrieve the notification status. + * + * @param connection Database connection + * @param notificationId Notification ID to retrieve + * @return Notification status by notification ID + * @throws FSEventNotificationException Exception when retrieving notification status + */ + boolean getNotificationStatus(Connection connection, String notificationId) throws FSEventNotificationException; + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventNotificationDAOImpl.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventNotificationDAOImpl.java new file mode 100644 index 00000000..f379632d --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventNotificationDAOImpl.java @@ -0,0 +1,415 @@ +/** + * 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.service.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.Notification; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationError; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationEvent; +import org.wso2.financial.services.accelerator.event.notifications.service.queries.EventNotificationSqlStatements; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Persisting event notifications to database. + */ +public class EventNotificationDAOImpl implements EventNotificationDAO { + + private static Log log = LogFactory.getLog(EventNotificationDAOImpl.class); + protected EventNotificationSqlStatements sqlStatements; + + public EventNotificationDAOImpl(EventNotificationSqlStatements eventNotificationSqlStatements) { + this.sqlStatements = eventNotificationSqlStatements; + } + + @Override + public String persistEventNotification(Connection connection, Notification notification, + ArrayList eventsList) + throws FSEventNotificationException { + + int result; + int[] noOfRows; + String persistEventNotification = sqlStatements.getStoreNotification(); + String persistEvents = sqlStatements.getStoreNotificationEvents(); + + try (PreparedStatement persistEventNotificationStmnt = + connection.prepareStatement(persistEventNotification); + PreparedStatement persistEventsStmt = connection.prepareStatement(persistEvents)) { + + log.debug("Setting parameters to prepared statement to add event notification "); + + persistEventNotificationStmnt.setString(1, notification.getNotificationId()); + persistEventNotificationStmnt.setString(2, notification.getClientId()); + persistEventNotificationStmnt.setString(3, notification.getResourceId()); + persistEventNotificationStmnt.setString(4, notification.getStatus()); + + // with result, we can determine whether the insertion was successful or not + result = persistEventNotificationStmnt.executeUpdate(); + + // to insert notification events + for (NotificationEvent event : eventsList) { + persistEventsStmt.setString(1, notification.getNotificationId()); + persistEventsStmt.setString(2, event.getEventType()); + persistEventsStmt.setString(3, event.getEventInformation().toString()); + persistEventsStmt.addBatch(); + } + noOfRows = persistEventsStmt.executeBatch(); + } catch (SQLException e) { + log.error(EventNotificationConstants.EVENT_NOTIFICATION_CREATION_ERROR, e); + throw new FSEventNotificationException(EventNotificationConstants. + EVENT_NOTIFICATION_CREATION_ERROR, e); + } + // Confirm that the data are updated successfully + if (result > 0 && noOfRows.length != 0) { + log.info("Created the event notification successfully"); + return notification.getNotificationId(); + } else { + throw new FSEventNotificationException("Failed to create the event notification."); + } + } + + @Override + public void updateNotificationStatusById(Connection connection, String notificationId, String notificationStatus) + throws FSEventNotificationException { + + String sql = sqlStatements.updateNotificationStatusQueryById(); + + try (PreparedStatement updateNotificationStatusById = connection.prepareStatement(sql)) { + Timestamp currentTimeStamp = new Timestamp(new Date().getTime()); + updateNotificationStatusById.setString(1, notificationStatus); + updateNotificationStatusById.setTimestamp(2, currentTimeStamp); + updateNotificationStatusById.setString(3, notificationId); + + int affectedRows = updateNotificationStatusById.executeUpdate(); + + if (affectedRows != 0) { + connection.commit(); + if (log.isDebugEnabled()) { + log.debug(String.format("Updated notification with Notification ID '%s'", + notificationId.replaceAll("[\r\n]", ""))); + } + } else { + if (log.isDebugEnabled()) { + log.debug(String.format("Failed updating notification with ID : '%s'", + notificationId.replaceAll("[\r\n]", ""))); + } + throw new FSEventNotificationException(String.format(EventNotificationConstants.DB_ERROR_UPDATING, + notificationId)); + } + } catch (SQLException e) { + log.error(String.format(EventNotificationConstants.DB_ERROR_UPDATING, + notificationId.replaceAll("[\r\n]", "")), e); + throw new FSEventNotificationException(String.format(EventNotificationConstants.DB_ERROR_UPDATING, + notificationId)); + } + } + + @Override + public void storeErrorNotification(Connection connection, NotificationError notificationError) + throws FSEventNotificationException { + + String storeErrorNotificationQuery = sqlStatements.storeErrorNotificationQuery(); + + try (PreparedStatement storeErrorNotificationPreparedStatement = + connection.prepareStatement(storeErrorNotificationQuery)) { + + storeErrorNotificationPreparedStatement.setString(1, notificationError. + getNotificationId()); + storeErrorNotificationPreparedStatement.setString(2, notificationError. + getErrorCode()); + storeErrorNotificationPreparedStatement.setString(3, notificationError. + getErrorDescription()); + + int affectedRows = storeErrorNotificationPreparedStatement.executeUpdate(); + if (affectedRows == 1) { + if (log.isDebugEnabled()) { + log.debug(String.format("Successfully stored error notification with ID:'%s'.", + notificationError.getNotificationId().replaceAll("[\r\n]", ""))); + } + } else { + if (log.isDebugEnabled()) { + log.debug(String.format("Failed store error notification with ID:'%s'.", + notificationError.getNotificationId().replaceAll("[\r\n]", ""))); + } + throw new FSEventNotificationException(EventNotificationConstants. + DB_FAILED_ERROR_NOTIFICATION_STORING + notificationError.getNotificationId()); + } + + } catch (SQLException e) { + throw new FSEventNotificationException(EventNotificationConstants. + DB_ERROR_STORING_ERROR_NOTIFICATION, e); + } + } + + @Override + public List getNotificationsByClientIdAndStatus(Connection connection, String clientId, + String status, int max) + throws FSEventNotificationException { + + List notificationList = new ArrayList<>(); + String sql = sqlStatements.getMaxNotificationsQuery(); + + try (PreparedStatement getNotificationsPreparedStatement = connection.prepareStatement(sql)) { + getNotificationsPreparedStatement.setString(1, clientId); + getNotificationsPreparedStatement.setString(2, status); + getNotificationsPreparedStatement.setInt(3, max); + + try (ResultSet notificationResultSet = getNotificationsPreparedStatement.executeQuery()) { + if (notificationResultSet.next()) { + + //bring pointer back to the top of the result set if not on the top + if (!notificationResultSet.isBeforeFirst()) { + notificationResultSet.beforeFirst(); + } + + //read event notifications from the result set + while (notificationResultSet.next()) { + Notification notification = new Notification(); + + notification.setNotificationId(notificationResultSet.getString + (EventNotificationConstants.NOTIFICATION_ID)); + notification.setClientId(notificationResultSet.getString + (EventNotificationConstants.CLIENT_ID)); + notification.setResourceId(notificationResultSet.getString + (EventNotificationConstants.RESOURCE_ID)); + notification.setStatus(notificationResultSet.getString + (EventNotificationConstants.STATUS)); + notification.setUpdatedTimeStamp((notificationResultSet.getTimestamp( + (EventNotificationConstants.UPDATED_TIMESTAMP)).getTime())); + + notificationList.add(notification); + } + notificationResultSet.close(); + getNotificationsPreparedStatement.close(); + + if (log.isDebugEnabled()) { + log.debug(String.format(EventNotificationConstants.RETRIEVED_NOTIFICATION_CLIENT, + clientId.replaceAll("[\r\n]", ""))); + } + } else { + if (log.isDebugEnabled()) { + log.debug(String.format(EventNotificationConstants.NO_NOTIFICATIONS_FOUND_CLIENT, + clientId.replaceAll("[\r\n]", ""))); + } + } + } + } catch (SQLException e) { + throw new FSEventNotificationException(String.format + (EventNotificationConstants.DB_ERROR_NOTIFICATION_RETRIEVE, clientId), e); + } + + return notificationList; + } + + @Override + public List getEventsByNotificationID(Connection connection, String notificationId) + throws FSEventNotificationException { + + List eventList = new ArrayList<>(); + String sql = sqlStatements.getEventsByNotificationIdQuery(); + + try (PreparedStatement getEventsPreparedStatement = connection.prepareStatement(sql)) { + + getEventsPreparedStatement.setString(1, notificationId); + + try (ResultSet eventsResultSet = getEventsPreparedStatement.executeQuery()) { + if (eventsResultSet.next()) { + + //bring pointer back to the top of the result set if not on the top + if (!eventsResultSet.isBeforeFirst()) { + eventsResultSet.beforeFirst(); + } + + //read event notifications from the result set + while (eventsResultSet.next()) { + NotificationEvent event = new NotificationEvent(); + event.setNotificationId(eventsResultSet.getString + (EventNotificationConstants.NOTIFICATION_ID)); + event.setEventType(eventsResultSet.getString + (EventNotificationConstants.EVENT_TYPE)); + event.setEventInformation(EventNotificationServiceUtil. + getEventJSONFromString(eventsResultSet.getString + (EventNotificationConstants.EVENT_INFO))); + eventList.add(event); + } + eventsResultSet.close(); + getEventsPreparedStatement.close(); + + if (log.isDebugEnabled()) { + log.debug(String.format(EventNotificationConstants.RETRIEVED_EVENTS_NOTIFICATION, + notificationId.replaceAll("[\r\n]", ""))); + } + } else { + if (log.isDebugEnabled()) { + log.debug(String.format(EventNotificationConstants.NO_EVENTS_NOTIFICATION_ID, + notificationId.replaceAll("[\r\n]", ""))); + } + } + } catch (SQLException e) { + log.error(String.format(EventNotificationConstants.PARSE_ERROR_NOTIFICATION_ID, + notificationId.replaceAll("[\r\n]", "")), e); + throw new FSEventNotificationException(String.format ( + EventNotificationConstants.PARSE_ERROR_NOTIFICATION_ID, notificationId), e); + } + } catch (SQLException e) { + log.error(String.format(EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, + notificationId.replaceAll("[\r\n]", "")), e); + throw new FSEventNotificationException(String.format + (EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, notificationId), e); + } + + + return eventList; + } + + @Override + public List getNotificationsByStatus(Connection connection, String status) + throws FSEventNotificationException { + + List notificationList = new ArrayList<>(); + String sql = sqlStatements.getNotificationsByState(); + try (PreparedStatement getNotificationsPreparedStatement = connection.prepareStatement(sql)) { + getNotificationsPreparedStatement.setString(1, status); + + try (ResultSet notificationResultSet = getNotificationsPreparedStatement.executeQuery()) { + if (notificationResultSet.next()) { + //bring pointer back to the top of the result set if not on the top + if (!notificationResultSet.isBeforeFirst()) { + notificationResultSet.beforeFirst(); + } + //read event notifications from the result set + while (notificationResultSet.next()) { + Notification notification = new Notification(); + notification.setNotificationId(notificationResultSet.getString + (EventNotificationConstants.NOTIFICATION_ID)); + notification.setClientId(notificationResultSet.getString + (EventNotificationConstants.CLIENT_ID)); + notification.setResourceId(notificationResultSet.getString + (EventNotificationConstants.RESOURCE_ID)); + notification.setStatus(notificationResultSet.getString + (EventNotificationConstants.STATUS)); + notification.setUpdatedTimeStamp((notificationResultSet.getTimestamp( + (EventNotificationConstants.UPDATED_TIMESTAMP)).getTime())); + notificationList.add(notification); + } + notificationResultSet.close(); + getNotificationsPreparedStatement.close(); + if (log.isDebugEnabled()) { + log.debug( + EventNotificationConstants.RETRIEVED_NOTIFICATION_CLIENT); + } + } else { + if (log.isDebugEnabled()) { + log.debug(EventNotificationConstants.NO_NOTIFICATIONS_FOUND_CLIENT); + } + } + } + } catch (SQLException e) { + throw new FSEventNotificationException(EventNotificationConstants.DB_ERROR_NOTIFICATION_RETRIEVE, e); + } + + return notificationList; + } + + @Override + public int getNotificationCountByClientIdAndStatus(Connection connection, String clientId, String eventStatus) + throws FSEventNotificationException { + + String sql = sqlStatements.getNotificationsCountQuery(); + + try (PreparedStatement getNotificationCount = connection.prepareStatement(sql)) { + + getNotificationCount.setString(1, clientId); + getNotificationCount.setString(2, eventStatus); + + try (ResultSet notificationCountResultSet = getNotificationCount.executeQuery()) { + if (notificationCountResultSet.next()) { + + int count = notificationCountResultSet.getInt("NOTIFICATION_COUNT"); + notificationCountResultSet.close(); + getNotificationCount.close(); + + if (log.isDebugEnabled()) { + log.debug(String.format("Retrieved notification count for client ID: '%s'. ", + clientId.replaceAll("[\r\n]", ""))); + } + + return count; + } else { + if (log.isDebugEnabled()) { + log.debug(String.format( + EventNotificationConstants.NO_NOTIFICATIONS_FOUND_CLIENT, + clientId.replaceAll("[\r\n]", ""))); + } + + return 0; + } + } + } catch (SQLException e) { + throw new FSEventNotificationException(String.format + (EventNotificationConstants.DB_ERROR_NOTIFICATION_RETRIEVE, clientId), e); + } + } + + @Override + public boolean getNotificationStatus(Connection connection, String notificationId) + throws FSEventNotificationException { + + boolean isOpenStatus = false; + + String sql = sqlStatements.getNotificationByNotificationId(); + try (PreparedStatement getNotificationStatus = connection.prepareStatement(sql)) { + getNotificationStatus.setString(1, notificationId); + + try (ResultSet notificationResultSet = getNotificationStatus.executeQuery()) { + if (notificationResultSet.next()) { + + if (EventNotificationConstants.OPEN.equals(notificationResultSet. + getString("STATUS"))) { + isOpenStatus = true; + } + + return isOpenStatus; + } else { + if (log.isDebugEnabled()) { + log.debug(String.format("No notifications found for notification ID - '%s'", + notificationId.replaceAll("[\r\n]", ""))); + } + } + } + } catch (SQLException e) { + throw new FSEventNotificationException(String.format + ("Error occurred while retrieving status for the notifications ID : '%s'.", + notificationId), e); + } + + return false; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventSubscriptionDAO.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventSubscriptionDAO.java new file mode 100644 index 00000000..a22ad7ed --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventSubscriptionDAO.java @@ -0,0 +1,120 @@ +/** + * 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.service.dao; + +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventSubscription; + +import java.sql.Connection; +import java.util.List; + +/** + * Event Notification Subscription DAO interface. + */ +public interface EventSubscriptionDAO { + + /** + * This method is used to store event notification subscription in the database. + * + * @param connection Database connection. + * @param eventSubscription EventSubscription object. + * @return EventSubscription object. + * @throws FSEventNotificationException Exception when storing event subscription + */ + EventSubscription storeEventSubscription(Connection connection, EventSubscription eventSubscription) + throws FSEventNotificationException; + + /** + * This method is used to store subscribed event types in the database. + * + * @param connection Database connection. + * @param subscriptionId Subscription ID. + * @param eventTypes Event types to be stored. + * @return List of strings with subscribed event types. + * @throws FSEventNotificationException Exception when storing subscribed event types + */ + List storeSubscribedEventTypes(Connection connection, String subscriptionId, List eventTypes) + throws FSEventNotificationException; + + /** + * This method is used to retrieve an event subscription by a subscription ID. + * + * @param connection Database connection. + * @param subscriptionId Subscription ID. + * @return EventSubscription model. + * @throws FSEventNotificationException Exception when retrieving event subscription by subscription ID + */ + EventSubscription getEventSubscriptionBySubscriptionId(Connection connection, String subscriptionId) + throws FSEventNotificationException; + + /** + * This method is used to retrieve all event subscriptions a client. + * + * @param connection Database connection. + * @param clientId Client ID. + * @return List of EventSubscription models. + * @throws FSEventNotificationException Exception when retrieving event subscriptions by client ID + */ + List getEventSubscriptionsByClientId(Connection connection, String clientId) + throws FSEventNotificationException; + + /** + * This method is used to retrieve all event subscriptions by event type. + * + * @param connection Database connection. + * @param eventType Event type that need to be subscribed by the retrieving subscriptions. + * @return List of EventSubscription models. + * @throws FSEventNotificationException Exception when retrieving event subscriptions by event type + */ + List getEventSubscriptionsByEventType(Connection connection, String eventType) + throws FSEventNotificationException; + + /** + * This method is used to update an event subscription. + * + * @param connection Database connection. + * @param eventSubscription eventSubscription object. + * @return true if update was successful. + * @throws FSEventNotificationException Exception when updating event subscription + */ + Boolean updateEventSubscription(Connection connection, EventSubscription eventSubscription) + throws FSEventNotificationException; + + /** + * This method is used to delete an event subscription. + * + * @param connection Database connection. + * @param subscriptionId Subscription ID. + * @return true if deletion was successful. + * @throws FSEventNotificationException Exception when deleting event subscription + */ + Boolean deleteEventSubscription(Connection connection, String subscriptionId) throws FSEventNotificationException; + + /** + * This method is used to delete subscribed event types of a subscription. + * + * @param connection Database connection. + * @param subscriptionId subscription ID. + * @return true if deletion was successful. + * @throws FSEventNotificationException Exception when deleting subscribed event types + */ + Boolean deleteSubscribedEventTypes(Connection connection, String subscriptionId) + throws FSEventNotificationException; + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventSubscriptionDAOImpl.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventSubscriptionDAOImpl.java new file mode 100644 index 00000000..d050d5ac --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/EventSubscriptionDAOImpl.java @@ -0,0 +1,304 @@ +/** + * 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.service.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventSubscription; +import org.wso2.financial.services.accelerator.event.notifications.service.queries.EventSubscriptionSqlStatements; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static java.sql.Statement.EXECUTE_FAILED; + +/** + * Default EventSubscriptionDAO Impl. + */ +public class EventSubscriptionDAOImpl implements EventSubscriptionDAO { + private static Log log = LogFactory.getLog(EventSubscriptionDAOImpl.class); + + protected EventSubscriptionSqlStatements sqlStatements; + + public EventSubscriptionDAOImpl(EventSubscriptionSqlStatements sqlStatements) { + this.sqlStatements = sqlStatements; + } + + public EventSubscription storeEventSubscription(Connection connection, EventSubscription eventSubscription) + throws FSEventNotificationException { + + int storeSubscriptionAffectedRows; + + UUID subscriptionId = UUID.randomUUID(); + long unixTime = Instant.now().getEpochSecond(); + eventSubscription.setSubscriptionId(subscriptionId.toString()); + eventSubscription.setTimeStamp(unixTime); + eventSubscription.setStatus(EventNotificationConstants.CREATED); + + final String sql = sqlStatements.storeEventSubscriptionQuery(); + try (PreparedStatement storeEventSubscriptionStatement = connection.prepareStatement(sql)) { + storeEventSubscriptionStatement.setString(1, eventSubscription.getSubscriptionId()); + storeEventSubscriptionStatement.setString(2, eventSubscription.getClientId()); + storeEventSubscriptionStatement.setString(3, eventSubscription.getCallbackUrl()); + storeEventSubscriptionStatement.setLong(4, eventSubscription.getTimeStamp()); + storeEventSubscriptionStatement.setString(5, eventSubscription.getSpecVersion()); + storeEventSubscriptionStatement.setString(6, eventSubscription.getStatus()); + storeEventSubscriptionStatement.setString(7, eventSubscription.getRequestData()); + storeSubscriptionAffectedRows = storeEventSubscriptionStatement.executeUpdate(); + if (storeSubscriptionAffectedRows == 0) { + log.error("Failed to store the event notification subscription."); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_STORING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when storing the event types of the subscription", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_STORING_EVENT_SUBSCRIPTION); + } + return eventSubscription; + } + + @Override + public List storeSubscribedEventTypes(Connection connection, String subscriptionId, List eventTypes) + throws FSEventNotificationException { + + final String sql = sqlStatements.storeSubscribedEventTypesQuery(); + try (PreparedStatement storeSubscribedEventTypesStatement = connection.prepareStatement(sql)) { + for (String eventType : eventTypes) { + storeSubscribedEventTypesStatement.setString(1, subscriptionId); + storeSubscribedEventTypesStatement.setString(2, eventType); + storeSubscribedEventTypesStatement.addBatch(); + } + int[] storeSubscribedEventTypesAffectedRows = storeSubscribedEventTypesStatement.executeBatch(); + for (int affectedRows : storeSubscribedEventTypesAffectedRows) { + if (affectedRows == 0 || affectedRows == EXECUTE_FAILED) { + log.error("Failed to store the subscribed event types."); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_STORING_EVENT_SUBSCRIPTION); + } + } + } catch (SQLException e) { + log.error("SQL exception when storing the subscribed event types.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_STORING_EVENT_SUBSCRIPTION); + } + log.debug("Stored the subscribed event types successfully."); + return eventTypes; + + } + + @Override + public EventSubscription getEventSubscriptionBySubscriptionId(Connection connection, String subscriptionId) + throws FSEventNotificationException { + EventSubscription retrievedSubscription = new EventSubscription(); + List eventTypes = new ArrayList<>(); + + final String sql = sqlStatements.getEventSubscriptionBySubscriptionIdQuery(); + try (PreparedStatement getEventSubscriptionBySubscriptionIdStatement = connection.prepareStatement(sql)) { + getEventSubscriptionBySubscriptionIdStatement.setString(1, subscriptionId); + try (ResultSet resultSet = getEventSubscriptionBySubscriptionIdStatement.executeQuery()) { + if (resultSet.next()) { + mapResultSetToEventSubscription(retrievedSubscription, resultSet); + resultSet.beforeFirst(); // Reset the cursor position to the beginning of the result set. + while (resultSet.next()) { + String eventType = resultSet.getString(EventNotificationConstants.EVENT_TYPE); + if (eventType != null) { + eventTypes.add(eventType); + } + } + retrievedSubscription.setEventTypes(eventTypes); + } else { + log.error("No event notification subscription found for the given subscription id."); + throw new FSEventNotificationException( + EventNotificationConstants.EVENT_SUBSCRIPTION_NOT_FOUND); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscription.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscription.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + return retrievedSubscription; + } + + @Override + public List getEventSubscriptionsByClientId(Connection connection, String clientId) + throws FSEventNotificationException { + List retrievedSubscriptions = new ArrayList<>(); + + final String sql = sqlStatements.getEventSubscriptionsByClientIdQuery(); + try (PreparedStatement getEventSubscriptionsByClientIdStatement = connection.prepareStatement(sql)) { + getEventSubscriptionsByClientIdStatement.setString(1, clientId); + try (ResultSet resultSet = getEventSubscriptionsByClientIdStatement.executeQuery()) { + if (resultSet.isBeforeFirst()) { + while (resultSet.next()) { + EventSubscription eventSubscription = new EventSubscription(); + List eventTypes = new ArrayList<>(); + mapResultSetToEventSubscription(eventSubscription, resultSet); + resultSet.previous(); + while (resultSet.next()) { + if (eventSubscription.getSubscriptionId().equals(resultSet. + getString(EventNotificationConstants.SUBSCRIPTION_ID))) { + if (resultSet.getString(EventNotificationConstants.EVENT_TYPE) != null) { + eventTypes.add(resultSet.getString(EventNotificationConstants.EVENT_TYPE)); + } + } else { + resultSet.previous(); + break; + } + } + eventSubscription.setEventTypes(eventTypes); + retrievedSubscriptions.add(eventSubscription); + } + log.debug("Retrieved the event notification subscriptions successfully."); + } + return retrievedSubscriptions; + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscriptions.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscriptions.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTIONS); + } + } + + @Override + public List getEventSubscriptionsByEventType(Connection connection, String eventType) + throws FSEventNotificationException { + List retrievedSubscriptions = new ArrayList<>(); + + final String sql = sqlStatements.getEventSubscriptionsByEventTypeQuery(); + try (PreparedStatement getEventSubscriptionsByClientIdAndEventTypeStatement = + connection.prepareStatement(sql)) { + getEventSubscriptionsByClientIdAndEventTypeStatement.setString(1, eventType); + try (ResultSet resultSet = getEventSubscriptionsByClientIdAndEventTypeStatement.executeQuery()) { + if (resultSet.isBeforeFirst()) { + while (resultSet.next()) { + EventSubscription eventSubscription = new EventSubscription(); + List eventTypes = new ArrayList<>(); + mapResultSetToEventSubscription(eventSubscription, resultSet); + resultSet.previous(); + while (resultSet.next()) { + if (eventSubscription.getSubscriptionId().equals(resultSet. + getString(EventNotificationConstants.SUBSCRIPTION_ID))) { + if (resultSet.getString(EventNotificationConstants.EVENT_TYPE) != null) { + eventTypes.add(resultSet.getString(EventNotificationConstants.EVENT_TYPE)); + } + } else { + resultSet.previous(); + break; + } + } + eventSubscription.setEventTypes(eventTypes); + retrievedSubscriptions.add(eventSubscription); + } + log.debug("Retrieved the event notification subscriptions successfully."); + } + return retrievedSubscriptions; + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscriptions.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscriptions.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTIONS); + } + } + + @Override + public Boolean updateEventSubscription(Connection connection, EventSubscription eventSubscription) + throws FSEventNotificationException { + boolean isUpdated = false; + final String sql = sqlStatements.updateEventSubscriptionQuery(); + try (PreparedStatement updateEventSubscriptionStatement = connection.prepareStatement(sql)) { + updateEventSubscriptionStatement.setString(1, eventSubscription.getCallbackUrl()); + updateEventSubscriptionStatement.setLong(2, Instant.now().getEpochSecond()); + updateEventSubscriptionStatement.setString(3, eventSubscription.getRequestData()); + updateEventSubscriptionStatement.setString(4, eventSubscription.getSubscriptionId()); + int affectedRows = updateEventSubscriptionStatement.executeUpdate(); + if (affectedRows > 0) { + log.debug("Event notification subscription is successfully updated."); + isUpdated = true; + } + } catch (SQLException e) { + log.error("SQL exception when updating event notification subscription", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_UPDATING_EVENT_SUBSCRIPTION); + } + return isUpdated; + } + + @Override + public Boolean deleteEventSubscription(Connection connection, String subscriptionId) + throws FSEventNotificationException { + + final String sql = sqlStatements.updateEventSubscriptionStatusQuery(); + try (PreparedStatement deleteEventSubscriptionStatement = connection.prepareStatement(sql)) { + deleteEventSubscriptionStatement.setString(1, "DELETED"); + deleteEventSubscriptionStatement.setString(2, subscriptionId); + int affectedRows = deleteEventSubscriptionStatement.executeUpdate(); + if (affectedRows == 0) { + log.debug("Failed deleting event notification subscription."); + return false; + } + log.debug("Event notification subscription is successfully deleted from the database."); + return true; + } catch (SQLException e) { + log.error("SQL exception when deleting event notification subscription data.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_DELETING_EVENT_SUBSCRIPTION); + } + } + + @Override + public Boolean deleteSubscribedEventTypes(Connection connection, String subscriptionId) + throws FSEventNotificationException { + boolean isDeleted = false; + int affectedRowsCount; + final String deleteEventTypesQuery = sqlStatements.deleteSubscribedEventTypesQuery(); + try (PreparedStatement deleteEventTypesStatement = connection.prepareStatement(deleteEventTypesQuery)) { + deleteEventTypesStatement.setString(1, subscriptionId); + affectedRowsCount = deleteEventTypesStatement.executeUpdate(); + if (affectedRowsCount > 0) { + log.debug("Successfully deleted the subscribed event types"); + isDeleted = true; + } + } catch (SQLException e) { + log.error("SQL exception when deleting subscribed event types. ", e); + throw new FSEventNotificationException( + "Error occurred while deleting the event notification subscription."); + } + return isDeleted; + } + + private void mapResultSetToEventSubscription(EventSubscription response, ResultSet resultSet) throws SQLException { + response.setSubscriptionId(resultSet.getString(EventNotificationConstants.SUBSCRIPTION_ID)); + response.setClientId(resultSet.getString(EventNotificationConstants.CLIENT_ID)); + response.setCallbackUrl(resultSet.getString(EventNotificationConstants.CALLBACK_URL)); + response.setTimeStamp(resultSet.getLong(EventNotificationConstants.TIME_STAMP)); + response.setSpecVersion(resultSet.getString(EventNotificationConstants.SPEC_VERSION)); + response.setStatus(resultSet.getString(EventNotificationConstants.STATUS)); + response.setRequestData(resultSet.getString(EventNotificationConstants.REQUEST)); + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/PostgreSqlEventNotificationDAOImpl.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/PostgreSqlEventNotificationDAOImpl.java new file mode 100644 index 00000000..8715f1c0 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/PostgreSqlEventNotificationDAOImpl.java @@ -0,0 +1,218 @@ +/** + * 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.service.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.financial.services.accelerator.common.util.Generated; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.Notification; +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationEvent; +import org.wso2.financial.services.accelerator.event.notifications.service.queries.EventNotificationSqlStatements; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * PostgreSql event polling dao class. + */ +@Generated(message = "Postgres Implementation") +public class PostgreSqlEventNotificationDAOImpl extends EventNotificationDAOImpl { + + private static Log log = LogFactory.getLog(PostgreSqlEventNotificationDAOImpl.class); + + public PostgreSqlEventNotificationDAOImpl(EventNotificationSqlStatements eventNotificationSqlStatements) { + super(eventNotificationSqlStatements); + } + + @Override + public List getNotificationsByClientIdAndStatus(Connection connection, String clientId, + String status, int max) + throws FSEventNotificationException { + + List notificationList = new ArrayList<>(); + String sql = sqlStatements.getMaxNotificationsQuery(); + + try (PreparedStatement getNotificationsPreparedStatement = connection.prepareStatement(sql, + ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + getNotificationsPreparedStatement.setString(1, clientId); + getNotificationsPreparedStatement.setString(2, status); + getNotificationsPreparedStatement.setInt(3, max); + + try (ResultSet notificationResultSet = getNotificationsPreparedStatement.executeQuery()) { + if (notificationResultSet.next()) { + + //bring pointer back to the top of the result set if not on the top + if (!notificationResultSet.isBeforeFirst()) { + notificationResultSet.beforeFirst(); + } + + //read event notifications from the result set + while (notificationResultSet.next()) { + Notification notification = new Notification(); + + notification.setNotificationId(notificationResultSet.getString + (EventNotificationConstants.NOTIFICATION_ID)); + notification.setClientId(notificationResultSet.getString + (EventNotificationConstants.CLIENT_ID)); + notification.setResourceId(notificationResultSet.getString + (EventNotificationConstants.RESOURCE_ID)); + notification.setStatus(notificationResultSet.getString + (EventNotificationConstants.STATUS)); + notification.setUpdatedTimeStamp((notificationResultSet.getTimestamp( + (EventNotificationConstants.UPDATED_TIMESTAMP)).getTime())); + + notificationList.add(notification); + } + notificationResultSet.close(); + getNotificationsPreparedStatement.close(); + + if (log.isDebugEnabled()) { + log.debug(String.format(EventNotificationConstants.RETRIEVED_NOTIFICATION_CLIENT, + clientId.replaceAll("[\r\n]", ""))); + } + + } else { + if (log.isDebugEnabled()) { + log.debug(String.format(EventNotificationConstants.NO_NOTIFICATIONS_FOUND_CLIENT, + clientId.replaceAll("[\r\n]", ""))); + } + } + } + } catch (SQLException e) { + throw new FSEventNotificationException(String.format + (EventNotificationConstants.DB_ERROR_NOTIFICATION_RETRIEVE, + clientId), e); + } + return notificationList; + } + + @Override + public List getEventsByNotificationID(Connection connection, String notificationId) + throws FSEventNotificationException { + + List eventList = new ArrayList<>(); + String sql = sqlStatements.getEventsByNotificationIdQuery(); + + try (PreparedStatement getEventsPreparedStatement = connection.prepareStatement(sql, + ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + + getEventsPreparedStatement.setString(1, notificationId); + + try (ResultSet eventsResultSet = getEventsPreparedStatement.executeQuery()) { + if (eventsResultSet.next()) { + + //bring pointer back to the top of the result set if not on the top + if (!eventsResultSet.isBeforeFirst()) { + eventsResultSet.beforeFirst(); + } + + //read event notifications from the result set + while (eventsResultSet.next()) { + NotificationEvent event = new NotificationEvent(); + event.setNotificationId(eventsResultSet.getString + (EventNotificationConstants.NOTIFICATION_ID)); + event.setEventType(eventsResultSet.getString + (EventNotificationConstants.EVENT_TYPE)); + event.setEventInformation(EventNotificationServiceUtil. + getEventJSONFromString(eventsResultSet.getString + (EventNotificationConstants.EVENT_INFO))); + eventList.add(event); + } + eventsResultSet.close(); + getEventsPreparedStatement.close(); + + if (log.isDebugEnabled()) { + log.debug(String.format(EventNotificationConstants.RETRIEVED_EVENTS_NOTIFICATION, + notificationId.replaceAll("[\r\n]", ""))); + } + } else { + if (log.isDebugEnabled()) { + log.debug(String.format(EventNotificationConstants.NO_EVENTS_NOTIFICATION_ID, + notificationId.replaceAll("[\r\n]", ""))); + } + } + } + } catch (SQLException e) { + log.error(String.format(EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, + notificationId.replaceAll("[\r\n]", "")), e); + throw new FSEventNotificationException(String.format + (EventNotificationConstants.DB_ERROR_EVENTS_RETRIEVE, notificationId), e); + } + + return eventList; + } + + @Override + public List getNotificationsByStatus(Connection connection, String status) + throws FSEventNotificationException { + + List notificationList = new ArrayList<>(); + String sql = sqlStatements.getMaxNotificationsQuery(); + + try (PreparedStatement getNotificationsPreparedStatement = connection.prepareStatement(sql, + ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + getNotificationsPreparedStatement.setString(1, status); + try (ResultSet notificationResultSet = getNotificationsPreparedStatement.executeQuery()) { + if (notificationResultSet.next()) { + //bring pointer back to the top of the result set if not on the top + if (!notificationResultSet.isBeforeFirst()) { + notificationResultSet.beforeFirst(); + } + //read event notifications from the result set + while (notificationResultSet.next()) { + Notification notification = new Notification(); + notification.setNotificationId(notificationResultSet.getString + (EventNotificationConstants.NOTIFICATION_ID)); + notification.setClientId(notificationResultSet.getString + (EventNotificationConstants.CLIENT_ID)); + notification.setResourceId(notificationResultSet.getString + (EventNotificationConstants.RESOURCE_ID)); + notification.setStatus(notificationResultSet.getString + (EventNotificationConstants.STATUS)); + notification.setUpdatedTimeStamp((notificationResultSet.getTimestamp( + (EventNotificationConstants.UPDATED_TIMESTAMP)).getTime())); + notificationList.add(notification); + } + notificationResultSet.close(); + getNotificationsPreparedStatement.close(); + if (log.isDebugEnabled()) { + log.debug( + EventNotificationConstants.RETRIEVED_NOTIFICATION_CLIENT); + } + } else { + if (log.isDebugEnabled()) { + log.debug( + EventNotificationConstants.NO_NOTIFICATIONS_FOUND_CLIENT); + } + } + } + } catch (SQLException e) { + throw new FSEventNotificationException( + EventNotificationConstants.DB_ERROR_NOTIFICATION_RETRIEVE, e); + } + return notificationList; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/PostgreSqlEventSubscriptionDAOImpl.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/PostgreSqlEventSubscriptionDAOImpl.java new file mode 100644 index 00000000..25d1396d --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dao/PostgreSqlEventSubscriptionDAOImpl.java @@ -0,0 +1,198 @@ +/** + * 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.service.dao; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventSubscription; +import org.wso2.financial.services.accelerator.event.notifications.service.queries.EventSubscriptionSqlStatements; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * Postgres SQL EventSubscriptionDAO Impl. + */ +public class PostgreSqlEventSubscriptionDAOImpl extends EventSubscriptionDAOImpl { + + private static final Log log = LogFactory.getLog(PostgreSqlEventSubscriptionDAOImpl.class); + + public PostgreSqlEventSubscriptionDAOImpl(EventSubscriptionSqlStatements sqlStatements) { + super(sqlStatements); + } + + @Override + public EventSubscription storeEventSubscription(Connection connection, EventSubscription eventSubscription) + throws FSEventNotificationException { + + int storeSubscriptionAffectedRows; + + UUID subscriptionId = UUID.randomUUID(); + long unixTime = Instant.now().getEpochSecond(); + eventSubscription.setSubscriptionId(subscriptionId.toString()); + eventSubscription.setTimeStamp(unixTime); + eventSubscription.setStatus(EventNotificationConstants.CREATED); + + final String sql = sqlStatements.storeEventSubscriptionQuery(); + try (PreparedStatement storeEventSubscriptionStatement = connection.prepareStatement(sql)) { + storeEventSubscriptionStatement.setString(1, eventSubscription.getSubscriptionId()); + storeEventSubscriptionStatement.setString(2, eventSubscription.getClientId()); + storeEventSubscriptionStatement.setString(3, eventSubscription.getCallbackUrl()); + storeEventSubscriptionStatement.setLong(4, eventSubscription.getTimeStamp()); + storeEventSubscriptionStatement.setString(5, eventSubscription.getSpecVersion()); + storeEventSubscriptionStatement.setString(6, eventSubscription.getStatus()); + storeEventSubscriptionStatement.setObject(7, eventSubscription.getRequestData(), + java.sql.Types.OTHER); + storeSubscriptionAffectedRows = storeEventSubscriptionStatement.executeUpdate(); + if (storeSubscriptionAffectedRows == 0) { + log.error("Failed to store the event notification subscription."); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_STORING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when storing the event types of the subscription", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_STORING_EVENT_SUBSCRIPTION); + } + return eventSubscription; + } + + @Override + public List getEventSubscriptionsByClientId(Connection connection, String clientId) + throws FSEventNotificationException { + List retrievedSubscriptions = new ArrayList<>(); + + final String sql = sqlStatements.getEventSubscriptionsByClientIdQuery(); + try (PreparedStatement getEventSubscriptionsByClientIdStatement = connection.prepareStatement(sql, + ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + getEventSubscriptionsByClientIdStatement.setString(1, clientId); + try (ResultSet resultSet = getEventSubscriptionsByClientIdStatement.executeQuery()) { + if (resultSet.isBeforeFirst()) { + while (resultSet.next()) { + EventSubscription eventSubscription = new EventSubscription(); + List eventTypes = new ArrayList<>(); + mapResultSetToEventSubscription(eventSubscription, resultSet); + resultSet.previous(); + while (resultSet.next()) { + if (eventSubscription.getSubscriptionId().equals(resultSet. + getString(EventNotificationConstants.SUBSCRIPTION_ID))) { + if (resultSet.getString(EventNotificationConstants.EVENT_TYPE) != null) { + eventTypes.add(resultSet.getString(EventNotificationConstants.EVENT_TYPE)); + } + } else { + resultSet.previous(); + break; + } + } + if (!eventTypes.isEmpty()) { + eventSubscription.setEventTypes(eventTypes); + } + retrievedSubscriptions.add(eventSubscription); + } + log.debug("Retrieved the event notification subscriptions successfully."); + } + return retrievedSubscriptions; + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscriptions.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscriptions.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTIONS); + } + } + + @Override + public EventSubscription getEventSubscriptionBySubscriptionId(Connection connection, String subscriptionId) + throws FSEventNotificationException { + EventSubscription retrievedSubscription = new EventSubscription(); + List eventTypes = new ArrayList<>(); + + final String sql = sqlStatements.getEventSubscriptionBySubscriptionIdQuery(); + try (PreparedStatement getEventSubscriptionBySubscriptionIdStatement = connection.prepareStatement(sql, + ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + getEventSubscriptionBySubscriptionIdStatement.setString(1, subscriptionId); + try (ResultSet resultSet = getEventSubscriptionBySubscriptionIdStatement.executeQuery()) { + if (resultSet.next()) { + mapResultSetToEventSubscription(retrievedSubscription, resultSet); + resultSet.beforeFirst(); // Reset the cursor position to the beginning of the result set. + while (resultSet.next()) { + String eventType = resultSet.getString(EventNotificationConstants.EVENT_TYPE); + if (eventType != null) { + eventTypes.add(eventType); + } + } + if (!eventTypes.isEmpty()) { + retrievedSubscription.setEventTypes(eventTypes); + } + } else { + log.error("No event notification subscription found for the given subscription id."); + throw new FSEventNotificationException( + EventNotificationConstants.EVENT_SUBSCRIPTION_NOT_FOUND); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscription.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + } catch (SQLException e) { + log.error("SQL exception when retrieving the event notification subscription.", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_RETRIEVING_EVENT_SUBSCRIPTION); + } + return retrievedSubscription; + } + + @Override + public Boolean updateEventSubscription(Connection connection, EventSubscription eventSubscription) + throws FSEventNotificationException { + boolean isUpdated = false; + final String sql = sqlStatements.updateEventSubscriptionQuery(); + try (PreparedStatement updateEventSubscriptionStatement = connection.prepareStatement(sql)) { + updateEventSubscriptionStatement.setString(1, eventSubscription.getCallbackUrl()); + updateEventSubscriptionStatement.setLong(2, Instant.now().getEpochSecond()); + updateEventSubscriptionStatement.setObject(3, eventSubscription.getRequestData(), + java.sql.Types.OTHER); + updateEventSubscriptionStatement.setString(4, eventSubscription.getSubscriptionId()); + int affectedRows = updateEventSubscriptionStatement.executeUpdate(); + if (affectedRows > 0) { + log.debug("Event notification subscription is successfully updated."); + isUpdated = true; + } + } catch (SQLException e) { + log.error("SQL exception when updating event notification subscription", e); + throw new FSEventNotificationException(EventNotificationConstants.ERROR_UPDATING_EVENT_SUBSCRIPTION); + } + return isUpdated; + } + + private void mapResultSetToEventSubscription(EventSubscription response, ResultSet resultSet) throws SQLException { + response.setSubscriptionId(resultSet.getString(EventNotificationConstants.SUBSCRIPTION_ID)); + response.setClientId(resultSet.getString(EventNotificationConstants.CLIENT_ID)); + response.setCallbackUrl(resultSet.getString(EventNotificationConstants.CALLBACK_URL)); + response.setTimeStamp(resultSet.getLong(EventNotificationConstants.TIME_STAMP)); + response.setSpecVersion(resultSet.getString(EventNotificationConstants.SPEC_VERSION)); + response.setStatus(resultSet.getString(EventNotificationConstants.STATUS)); + response.setRequestData(resultSet.getString(EventNotificationConstants.REQUEST)); + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dto/EventPollingDTO.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dto/EventPollingDTO.java new file mode 100644 index 00000000..500e5fb9 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dto/EventPollingDTO.java @@ -0,0 +1,75 @@ +/** + * 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.service.dto; + +import org.wso2.financial.services.accelerator.event.notifications.service.model.NotificationError; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Event Polling DTO. + */ +public class EventPollingDTO { + + //Set to true by default as WSO2 Financial Services don't support long polling + private final Boolean returnImmediately = true; + private String clientId = null; + private int maxEvents = 0; + private List ack = new ArrayList(); + private Map errors = new HashMap(); + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public Boolean getReturnImmediately() { + return returnImmediately; + } + + public int getMaxEvents() { + return maxEvents; + } + + public void setMaxEvents(int maxEvents) { + this.maxEvents = maxEvents; + } + + public List getAck() { + return ack; + } + + public void setAck(String ack) { + this.ack.add(ack); + } + + public Map getErrors() { + return errors; + } + + public void setErrors(String notificationId, NotificationError errorNotification) { + this.errors.put(notificationId, errorNotification); + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dto/EventSubscriptionDTO.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dto/EventSubscriptionDTO.java new file mode 100644 index 00000000..4b3b576d --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dto/EventSubscriptionDTO.java @@ -0,0 +1,81 @@ +/** + * 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.service.dto; + +import java.util.List; + +/** + * Event Subscription DTO. + */ +public class EventSubscriptionDTO { + private String clientId = null; + private String subscriptionId = null; + private String callbackUrl = null; + private String specVersion = null; + private List eventTypes = null; + private String requestData = null; + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getSubscriptionId() { + return subscriptionId; + } + + public void setSubscriptionId(String subscriptionId) { + this.subscriptionId = subscriptionId; + } + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + + public String getSpecVersion() { + return specVersion; + } + + public void setSpecVersion(String specVersion) { + this.specVersion = specVersion; + } + + public List getEventTypes() { + return eventTypes; + } + + public void setEventTypes(List eventTypes) { + this.eventTypes = eventTypes; + } + + public String getRequestData() { + return requestData; + } + + public void setRequestData(String requestData) { + this.requestData = requestData; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dto/NotificationCreationDTO.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dto/NotificationCreationDTO.java new file mode 100644 index 00000000..f75c58ab --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/dto/NotificationCreationDTO.java @@ -0,0 +1,59 @@ +/** + * 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.service.dto; + +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Map; + +/** + * Event Creation DTO. + */ +public class NotificationCreationDTO { + + private Map events = new HashMap(); + private String clientId = null; + private String resourceId = null; + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getResourceId() { + return resourceId; + } + + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + public Map getEventPayload() { + return this.events; + } + + public void setEventPayload(String notificationType, JSONObject notificationInfo) { + this.events.put(notificationType, notificationInfo); + } +} + diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/exception/FSEventNotificationException.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/exception/FSEventNotificationException.java new file mode 100644 index 00000000..8b7a5cdb --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/exception/FSEventNotificationException.java @@ -0,0 +1,56 @@ +/** + * 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.service.exception; + +import org.wso2.financial.services.accelerator.common.exception.FinancialServicesException; + +/** + * Event Notification Exceptions. + */ +public class FSEventNotificationException extends FinancialServicesException { + + private int status; + + public FSEventNotificationException(String message) { + super(message); + } + + public FSEventNotificationException(int status, String message) { + + super(message); + this.status = status; + } + public FSEventNotificationException(int status, String message, Throwable e) { + + super(message, e); + this.status = status; + } + + public FSEventNotificationException(String message, Throwable e) { + super(message, e); + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/DefaultEventCreationServiceHandler.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/DefaultEventCreationServiceHandler.java new file mode 100644 index 00000000..3cfc755b --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/DefaultEventCreationServiceHandler.java @@ -0,0 +1,103 @@ +/** + * 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.service.handler; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpStatus; +import org.json.JSONObject; +import org.wso2.financial.services.accelerator.common.exception.ConsentManagementException; +import org.wso2.financial.services.accelerator.consent.mgt.dao.models.ConsentResource; +import org.wso2.financial.services.accelerator.consent.mgt.service.impl.ConsentCoreServiceImpl; +import org.wso2.financial.services.accelerator.event.notifications.service.EventCreationService; +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.model.EventCreationResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +/** + * This is to handle FS Event Creation. + */ +public class DefaultEventCreationServiceHandler implements EventCreationServiceHandler { + + private static final Log log = LogFactory.getLog(DefaultEventCreationServiceHandler.class); + private EventCreationService eventCreationService = new EventCreationService(); + + public void setEventCreationService(EventCreationService eventCreationService) { + this.eventCreationService = eventCreationService; + } + + /** + * This method is used to publish FS events in the accelerator database. + * + * @param notificationCreationDTO Notification details DTO + * @return EventCreationResponse Response after event creation + */ + public EventCreationResponse publishEvent(NotificationCreationDTO notificationCreationDTO) + throws FSEventNotificationException { + + //validate if the resourceID is existing + ConsentResource consentResource = null; + ConsentCoreServiceImpl consentCoreService = EventNotificationServiceUtil.getConsentCoreServiceImpl(); + + try { + consentResource = consentCoreService.getConsent(notificationCreationDTO.getResourceId(), + false); + + if (log.isDebugEnabled()) { + log.debug("Consent resource available for resource ID " + + consentResource.getConsentID().replaceAll("[\r\n]", "")); + } + } catch (ConsentManagementException e) { + String errorMsg = String.format("A resource was not found for the resource id : '%s' in the database. ", + notificationCreationDTO.getResourceId().replaceAll("[\r\n]", "")); + log.error(errorMsg, e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, errorMsg, e); + } + + //validate if the clientID is existing + try { + EventNotificationServiceUtil.validateClientId(notificationCreationDTO.getClientId()); + + } catch (FSEventNotificationException e) { + String errorMsg = String.format("A client was not found" + " for the client id : '%s' in the database. ", + notificationCreationDTO.getClientId().replaceAll("[\r\n]", "")); + log.error(errorMsg, e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, errorMsg, e); + } + + String registrationResponse = ""; + try { + registrationResponse = eventCreationService.publishEventNotification(notificationCreationDTO); + JSONObject responseJSON = new JSONObject(); + responseJSON.put(EventNotificationConstants.NOTIFICATIONS_ID, registrationResponse); + + EventCreationResponse eventCreationResponse = new EventCreationResponse(); + eventCreationResponse.setStatus(EventNotificationConstants.CREATED); + eventCreationResponse.setResponseBody(responseJSON); + return eventCreationResponse; + + } catch (FSEventNotificationException e) { + log.error("FS Event Notification Creation error", e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, "FS Event Notification Creation error", + e); + } + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/DefaultEventPollingServiceHandler.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/DefaultEventPollingServiceHandler.java new file mode 100644 index 00000000..19237fb1 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/DefaultEventPollingServiceHandler.java @@ -0,0 +1,113 @@ +/** + * 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.service.handler; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpStatus; +import org.json.JSONObject; +import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigParser; +import org.wso2.financial.services.accelerator.common.util.Generated; +import org.wso2.financial.services.accelerator.event.notifications.service.EventPollingService; +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.model.AggregatedPollingResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventPolling; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventPollingResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +/** + * This is the service handler for event polling. + */ +public class DefaultEventPollingServiceHandler implements EventPollingServiceHandler { + + private static final Log log = LogFactory.getLog(DefaultEventPollingServiceHandler.class); + + public void setEventPollingService(EventPollingService eventPollingService) { + this.eventPollingService = eventPollingService; + } + + private EventPollingService eventPollingService = new EventPollingService(); + + + /** + * This method is used to Poll Events as per request params. + * @param eventPollingDTO Event polling DTO + * @return EventPollingResponse + */ + public EventPollingResponse pollEvents(EventPollingDTO eventPollingDTO) throws FSEventNotificationException { + + //Validate clientID of the polling request + try { + EventNotificationServiceUtil.validateClientId(eventPollingDTO.getClientId()); + } catch (FSEventNotificationException e) { + String errorMessage = String.format("A client was not found for the client id : '%s' in the database. ", + eventPollingDTO.getClientId().replaceAll("[\r\n]", "")); + log.error(errorMessage, e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, errorMessage, e); + } + + EventPolling eventPolling = mapEventPollingDtoToModel(eventPollingDTO); + //Poll events + try { + AggregatedPollingResponse aggregatedPollingResponse = eventPollingService.pollEvents(eventPolling); + + EventPollingResponse eventPollingResponse = new EventPollingResponse(); + eventPollingResponse.setStatus(aggregatedPollingResponse.getStatus()); + eventPollingResponse.setResponseBody(getPollingResponseJSON(aggregatedPollingResponse)); + return eventPollingResponse; + } catch (FSEventNotificationException e) { + log.error("OB Event Notification error" , e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, e.getMessage(), e); + } + + } + + /** + * This method will map the event subscription DTO to event subscription model + * to be passed to the dao layer. + * + * @param eventPollingDTO Event polling DTO + * @return EventPolling Event polling Model mapped + */ + private EventPolling mapEventPollingDtoToModel(EventPollingDTO eventPollingDTO) { + + EventPolling eventPolling = new EventPolling(); + eventPolling.setClientId(eventPollingDTO.getClientId()); + eventPolling.setMaxEvents(eventPollingDTO.getMaxEvents()); + eventPolling.setReturnImmediately(eventPollingDTO.getReturnImmediately()); + eventPolling.setSetsToReturn(FinancialServicesConfigParser.getInstance().getNumberOfSetsToReturn()); + eventPollingDTO.getAck().forEach(eventPolling::setAck); + eventPollingDTO.getErrors().forEach(eventPolling::setErrors); + + return eventPolling; + } + + @Generated(message = "Private method tested when testing the invoked method") + private JSONObject getPollingResponseJSON(AggregatedPollingResponse aggregatedPollingResponse) { + + JSONObject responseJSON = new JSONObject(); + responseJSON.put(EventNotificationConstants.SETS, aggregatedPollingResponse.getSets()); + responseJSON.put(EventNotificationConstants.MORE_AVAILABLE, + aggregatedPollingResponse.isMoreAvailable()); + return responseJSON; + } + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/DefaultEventSubscriptionServiceHandler.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/DefaultEventSubscriptionServiceHandler.java new file mode 100644 index 00000000..7488ec42 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/DefaultEventSubscriptionServiceHandler.java @@ -0,0 +1,284 @@ +/** + * 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.service.handler; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpStatus; +import org.json.JSONObject; +import org.wso2.financial.services.accelerator.event.notifications.service.EventSubscriptionService; +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.model.EventSubscription; +import org.wso2.financial.services.accelerator.event.notifications.service.model.EventSubscriptionResponse; +import org.wso2.financial.services.accelerator.event.notifications.service.util.EventNotificationServiceUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * This is the default service handler for event notification subscription. + */ +public class DefaultEventSubscriptionServiceHandler implements EventSubscriptionServiceHandler { + private static final Log log = LogFactory.getLog(DefaultEventSubscriptionServiceHandler.class); + + private EventSubscriptionService eventSubscriptionService = new EventSubscriptionService(); + + public void setEventSubscriptionService(EventSubscriptionService eventSubscriptionService) { + this.eventSubscriptionService = eventSubscriptionService; + } + + @Override + public EventSubscriptionResponse createEventSubscription(EventSubscriptionDTO eventSubscriptionRequestDto) + throws FSEventNotificationException { + + try { + EventNotificationServiceUtil.validateClientId(eventSubscriptionRequestDto.getClientId()); + + } catch (FSEventNotificationException e) { + String errorMsg = String.format("A client was not found" + " for the client id : '%s' in the database. ", + eventSubscriptionRequestDto.getClientId().replaceAll("[\r\n]", "")); + log.error(errorMsg, e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, errorMsg, e); + } + + try { + EventSubscription eventSubscriptionCreateResponse = eventSubscriptionService. + createEventSubscription(mapEventSubscriptionDtoToModel(eventSubscriptionRequestDto)); + + EventSubscriptionResponse eventSubscriptionResponse = new EventSubscriptionResponse(); + eventSubscriptionResponse.setResponseStatus(HttpStatus.SC_CREATED); + eventSubscriptionResponse + .setResponseBody(mapSubscriptionModelToResponseJson(eventSubscriptionCreateResponse)); + return eventSubscriptionResponse; + } catch (FSEventNotificationException e) { + log.error("Error occurred while creating event subscription", e); + throw new FSEventNotificationException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); + } + } + + @Override + public EventSubscriptionResponse getEventSubscription(String clientId, String subscriptionId) + throws FSEventNotificationException { + + try { + EventNotificationServiceUtil.validateClientId(clientId); + + } catch (FSEventNotificationException e) { + String errorMsg = String.format("A client was not found" + " for the client id : '%s' in the database. ", + clientId.replaceAll("[\r\n]", "")); + log.error(errorMsg, e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, errorMsg, e); + } + + try { + EventSubscription eventSubscription = eventSubscriptionService. + getEventSubscriptionBySubscriptionId(subscriptionId); + + EventSubscriptionResponse eventSubscriptionResponse = new EventSubscriptionResponse(); + eventSubscriptionResponse.setResponseStatus(HttpStatus.SC_OK); + eventSubscriptionResponse.setResponseBody(mapSubscriptionModelToResponseJson(eventSubscription)); + return eventSubscriptionResponse; + } catch (FSEventNotificationException e) { + log.error("Error occurred while retrieving event subscription", e); + if (e.getMessage().equals(EventNotificationConstants.EVENT_SUBSCRIPTION_NOT_FOUND)) { + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, e.getMessage(), e); + } else { + throw new FSEventNotificationException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); + } + } + } + + @Override + public EventSubscriptionResponse getAllEventSubscriptions(String clientId) + throws FSEventNotificationException { + + try { + EventNotificationServiceUtil.validateClientId(clientId); + + } catch (FSEventNotificationException e) { + String errorMsg = String.format("A client was not found" + " for the client id : '%s' in the database. ", + clientId.replaceAll("[\r\n]", "")); + log.error(errorMsg, e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, errorMsg, e); + } + + try { + List eventSubscriptionList = eventSubscriptionService. + getEventSubscriptionsByClientId(clientId); + List eventSubscriptionResponseList = new ArrayList<>(); + for (EventSubscription eventSubscription : eventSubscriptionList) { + eventSubscriptionResponseList.add(mapSubscriptionModelToResponseJson(eventSubscription)); + } + + EventSubscriptionResponse eventSubscriptionResponse = new EventSubscriptionResponse(); + eventSubscriptionResponse.setResponseStatus(HttpStatus.SC_OK); + eventSubscriptionResponse.setResponseBody(eventSubscriptionResponseList); + return eventSubscriptionResponse; + } catch (FSEventNotificationException e) { + log.error("Error occurred while retrieving event subscriptions", e); + throw new FSEventNotificationException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); + + } + } + + @Override + public EventSubscriptionResponse getEventSubscriptionsByEventType(String clientId, String eventType) + throws FSEventNotificationException { + + try { + EventNotificationServiceUtil.validateClientId(clientId); + + } catch (FSEventNotificationException e) { + String errorMsg = String.format("A client was not found" + " for the client id : '%s' in the database. ", + clientId.replaceAll("[\r\n]", "")); + log.error(errorMsg, e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, errorMsg, e); + } + + try { + List eventSubscriptionList = eventSubscriptionService. + getEventSubscriptionsByEventType(eventType); + List eventSubscriptionResponseList = new ArrayList<>(); + for (EventSubscription eventSubscription : eventSubscriptionList) { + eventSubscriptionResponseList.add(mapSubscriptionModelToResponseJson(eventSubscription)); + } + + + EventSubscriptionResponse eventSubscriptionResponse = new EventSubscriptionResponse(); + eventSubscriptionResponse.setResponseStatus(HttpStatus.SC_OK); + eventSubscriptionResponse.setResponseBody(eventSubscriptionResponseList); + return eventSubscriptionResponse; + } catch (FSEventNotificationException e) { + log.error("Error occurred while retrieving event subscriptions", e); + throw new FSEventNotificationException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); + } + } + + @Override + public EventSubscriptionResponse updateEventSubscription(EventSubscriptionDTO eventSubscriptionUpdateRequestDto) + throws FSEventNotificationException { + + EventSubscriptionResponse eventSubscriptionResponse = new EventSubscriptionResponse(); + + try { + EventNotificationServiceUtil.validateClientId(eventSubscriptionUpdateRequestDto.getClientId()); + + } catch (FSEventNotificationException e) { + String errorMsg = String.format("A client was not found" + " for the client id : '%s' in the database. ", + eventSubscriptionUpdateRequestDto.getClientId().replaceAll("[\r\n]", "")); + log.error(errorMsg, e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, errorMsg, e); + } + + EventSubscription eventSubscription = mapEventSubscriptionDtoToModel(eventSubscriptionUpdateRequestDto); + + try { + Boolean isUpdated = eventSubscriptionService.updateEventSubscription(eventSubscription); + if (!isUpdated) { + log.error("Event subscription not found."); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, "Event subscription not found."); + } + eventSubscriptionResponse.setResponseStatus(HttpStatus.SC_OK); + EventSubscription eventSubscriptionUpdateResponse = eventSubscriptionService. + getEventSubscriptionBySubscriptionId(eventSubscriptionUpdateRequestDto.getSubscriptionId()); + eventSubscriptionResponse. + setResponseBody(mapSubscriptionModelToResponseJson(eventSubscriptionUpdateResponse)); + return eventSubscriptionResponse; + } catch (FSEventNotificationException e) { + log.error("Error occurred while updating event subscription", e); + throw new FSEventNotificationException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); + } + } + + @Override + public EventSubscriptionResponse deleteEventSubscription(String clientId, String subscriptionId) + throws FSEventNotificationException { + + try { + EventNotificationServiceUtil.validateClientId(clientId); + + } catch (FSEventNotificationException e) { + String errorMsg = String.format("A client was not found" + " for the client id : '%s' in the database. ", + clientId.replaceAll("[\r\n]", "")); + log.error(errorMsg, e); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, errorMsg, e); + } + + try { + Boolean isDeleted = eventSubscriptionService.deleteEventSubscription(subscriptionId); + if (!isDeleted) { + log.error("Event subscription not found"); + throw new FSEventNotificationException(HttpStatus.SC_BAD_REQUEST, "Event subscription not found"); + } + + EventSubscriptionResponse eventSubscriptionResponse = new EventSubscriptionResponse(); + eventSubscriptionResponse.setResponseStatus(HttpStatus.SC_NO_CONTENT); + return eventSubscriptionResponse; + } catch (FSEventNotificationException e) { + log.error("Error occurred while deleting event subscription", e); + throw new FSEventNotificationException(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e); + } + } + + /** + * This method will map the event subscription DTO to event subscription model + * to be passed to the dao layer. + * + * @param eventSubscriptionDTO Event Subscription DTO + * @return EventSubscription Event Subscription Model mapped + */ + private EventSubscription mapEventSubscriptionDtoToModel(EventSubscriptionDTO eventSubscriptionDTO) { + EventSubscription eventSubscription = new EventSubscription(); + + eventSubscription.setSubscriptionId(eventSubscriptionDTO.getSubscriptionId()); + eventSubscription.setEventTypes(eventSubscriptionDTO.getEventTypes()); + eventSubscription.setCallbackUrl(eventSubscriptionDTO.getCallbackUrl()); + eventSubscription.setSpecVersion(eventSubscriptionDTO.getSpecVersion()); + eventSubscription.setClientId(eventSubscriptionDTO.getClientId()); + eventSubscription.setRequestData(eventSubscriptionDTO.getRequestData()); + return eventSubscription; + } + + /** + * This method is used to create the response model from the event subscription model. + * + * @param eventSubscription Event Subscription Model + * @return EventSubscriptionResponse containing mapped subscription + */ + public JSONObject mapSubscriptionModelToResponseJson(EventSubscription eventSubscription) { + JSONObject responsePayload = new JSONObject(); + + if (eventSubscription.getSubscriptionId() != null) { + responsePayload.put(EventNotificationConstants.SUBSCRIPTION_ID_PARAM, + eventSubscription.getSubscriptionId()); + } + if (eventSubscription.getCallbackUrl() != null) { + responsePayload.put(EventNotificationConstants.CALLBACK_URL_PARAM, eventSubscription.getCallbackUrl()); + } + if (eventSubscription.getSpecVersion() != null) { + responsePayload.put(EventNotificationConstants.VERSION_PARAM, eventSubscription.getSpecVersion()); + } + if (eventSubscription.getEventTypes() != null) { + responsePayload.put(EventNotificationConstants.EVENT_TYPES_PARAM, eventSubscription.getEventTypes()); + } + return responsePayload; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/EventCreationServiceHandler.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/EventCreationServiceHandler.java new file mode 100644 index 00000000..64480acc --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/EventCreationServiceHandler.java @@ -0,0 +1,41 @@ +/** + * 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.service.handler; + +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.model.EventCreationResponse; + +/** + * Event creation service handler is used to map the creation request and validate the date before + * calling the service. In need of a custom handling this class can be extended and the extended class + * can be added to the deployment.toml under event_creation_handler to execute the specific class. + */ +public interface EventCreationServiceHandler { + /** + * This method is used to publish FS events in the accelerator database. The method is a generic + * method that is used to persist data into the FS_NOTIFICATION and FS_NOTIFICATION_EVENT tables. + * @param notificationCreationDTO Notification details DTO + * @return For successful request the API will return a JSON with the notificationID + * @throws FSEventNotificationException Exception when creating event + */ + EventCreationResponse publishEvent(NotificationCreationDTO notificationCreationDTO) + throws FSEventNotificationException; + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/EventPollingServiceHandler.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/EventPollingServiceHandler.java new file mode 100644 index 00000000..a87639a1 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/EventPollingServiceHandler.java @@ -0,0 +1,41 @@ +/** + * 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.service.handler; + +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.model.EventPollingResponse; + +/** + * EventPolling Service handler is used to validate and map the polling request to the DTO before calling the + * polling service. For custom validations this class can be extended and the extended class + * can be added to the deployment.toml under event_polling_handler to execute the specific class. + */ +public interface EventPollingServiceHandler { + /** + * This method follows the IETF Specification for SET delivery over HTTP. + * The method supports event acknowledgment in both positive and negative. + * Also, can be used to POLL for available OPEN notifications. + * @param eventPollingDTO Event polling DTO + * @return EventPollingResponse to the polling endpoint. + * @throws FSEventNotificationException Exception when polling events + */ + EventPollingResponse pollEvents(EventPollingDTO eventPollingDTO) throws FSEventNotificationException; + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/EventSubscriptionServiceHandler.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/EventSubscriptionServiceHandler.java new file mode 100644 index 00000000..6a5178fa --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/handler/EventSubscriptionServiceHandler.java @@ -0,0 +1,96 @@ +/** + * 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.service.handler; + +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.model.EventSubscriptionResponse; + +/** + * EventSubscription Service handler is used to validate subscription requests before calling the + * subscription service. For custom validations this class can be extended and the extended class + * can be added to the deployment.toml under event_subscription_handler to execute the specific class. + */ +public interface EventSubscriptionServiceHandler { + + /** + * This method is used to create event subscriptions in the accelerator database. The method is a generic + * method that is used to persist data into the NOTIFICATION_SUBSCRIPTION and NOTIFICATION_SUBSCRIPTION_EVENT + * tables. + * + * @param eventSubscriptionRequestDto The request DTO that contains the subscription details. + * @return For successful request the API will return a JSON with the subscriptionId + * @throws FSEventNotificationException Exception when creating event subscription. + */ + EventSubscriptionResponse createEventSubscription(EventSubscriptionDTO eventSubscriptionRequestDto) + throws FSEventNotificationException; + + /** + * This method is used to retrieve an event subscription by its subscription ID. + * + * @param clientId The client ID of the subscription. + * @param subscriptionId The subscription ID of the subscription. + * @return For successful request the API will return a JSON with the retrieved Subscription. + * @throws FSEventNotificationException Exception when retrieving event subscription. + */ + EventSubscriptionResponse getEventSubscription(String clientId, String subscriptionId) + throws FSEventNotificationException; + + /** + * This method is used to retrieve all event subscriptions of a client. + * + * @param clientId The client ID of the subscription. + * @return For successful request the API will return a JSON with the retrieved Subscriptions. + * @throws FSEventNotificationException Exception when retrieving event subscriptions. + */ + EventSubscriptionResponse getAllEventSubscriptions(String clientId) throws FSEventNotificationException; + + /** + * This method is used to retrieve all event subscriptions by event type. + * + * @param clientId The client ID of the subscription. + * @param eventType The event type that needs to be subscribed by the retrieving subscriptions. + * @return For successful request the API will return a JSON with the retrieved Subscriptions. + * @throws FSEventNotificationException Exception when retrieving event subscriptions. + */ + EventSubscriptionResponse getEventSubscriptionsByEventType(String clientId, String eventType) + throws FSEventNotificationException; + + /** + * This method is used to update an event subscription. + * + * @param eventSubscriptionUpdateRequestDto The request DTO that contains the updating subscription details. + * @return For successful request the API will return a JSON with the updated Subscription. + * @throws FSEventNotificationException Exception when updating event subscription. + */ + EventSubscriptionResponse updateEventSubscription(EventSubscriptionDTO eventSubscriptionUpdateRequestDto) + throws FSEventNotificationException; + + /** + * This method is used to delete an event subscription. + * + * @param clientId The client ID of the subscription. + * @param subscriptionId The subscription ID of the subscription. + * @return For successful request the API will an OK response. + * @throws FSEventNotificationException Exception when deleting event subscription. + */ + EventSubscriptionResponse deleteEventSubscription(String clientId, String subscriptionId) + throws FSEventNotificationException; + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/internal/EventNotificationComponent.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/internal/EventNotificationComponent.java new file mode 100644 index 00000000..d6124767 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/internal/EventNotificationComponent.java @@ -0,0 +1,98 @@ +/** + * 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.service.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.wso2.carbon.identity.oauth2.OAuth2Service; +import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigParser; +import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigurationService; + +/** + * The Component class for activating event notification osgi service. + */ +@Component( + name = "org.wso2.financial.services.accelerator.event.notifications.service.internal.EventNotificationComponent", + immediate = true) +public class EventNotificationComponent { + private static Log log = LogFactory.getLog(EventNotificationComponent.class); + + @Activate + protected void activate(ComponentContext context) { + log.debug("Event Notification Service Component Activated"); + + // Check if realtime event notification enabled + if (FinancialServicesConfigParser.getInstance().isRealtimeEventNotificationEnabled()) { + /* + * Initialize the blocking queue for storing the realtime event notifications + * Initialize the quartz job for consuming the realtime event notifications + * Initialize the thread for producing the open state realtime event notifications + */ + //TODO: +// new Thread(new RealtimeEventNotificationLoaderService()).start(); +// new PeriodicalEventNotificationConsumerJobActivator().activate(); + } + } + + /** + * Setters for the descendent OSGI services of the EventNotificationComponent. + * This is added to run the EventNotification OSGI component after the Common module + * @param configService OpenBankingConfigurationService + */ + @Reference( + service = FinancialServicesConfigurationService.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetConfigService" + ) + public void setConfigService(FinancialServicesConfigurationService configService) { + EventNotificationDataHolder.getInstance().setFinancialServicesConfigurationService(configService); + } + + public void unsetConfigService(FinancialServicesConfigurationService configService) { + EventNotificationDataHolder.getInstance().setFinancialServicesConfigurationService(null); + } + + /** + * Setters for the descendent OSGI services of the EventNotificationComponent. + * This is added to run the EventNotification OSGI component after the OAuth2Service + */ + @Reference( + service = OAuth2Service.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetOAuth2Service" + ) + + /** + * Setters for the descendent OSGI services of the EventNotificationComponent. + * @param oAuth2Service OAuth2Service + */ + public void setOAuth2Service(OAuth2Service oAuth2Service) { + } + + public void unsetOAuth2Service(OAuth2Service oAuth2Service) { + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/internal/EventNotificationDataHolder.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/internal/EventNotificationDataHolder.java new file mode 100644 index 00000000..d16bb2f7 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/internal/EventNotificationDataHolder.java @@ -0,0 +1,73 @@ +/** + * 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.service.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigurationService; + +/** + * Data holder for Open Banking Event Notifications. + */ +public class EventNotificationDataHolder { + private static Log log = LogFactory.getLog(EventNotificationDataHolder.class); + private static volatile EventNotificationDataHolder instance; +// private volatile LinkedBlockingQueue realtimeEventNotificationQueue; + private FinancialServicesConfigurationService configService; + + private EventNotificationDataHolder() { + //TODO +// this.realtimeEventNotificationQueue = new LinkedBlockingQueue<>(); + } + + /** + * Return a singleton instance of the data holder. + * + * @return A singleton instance of the data holder + */ + public static synchronized EventNotificationDataHolder getInstance() { + if (instance == null) { + synchronized (EventNotificationDataHolder.class) { + if (instance == null) { + instance = new EventNotificationDataHolder(); + } + } + } + return instance; + } + +// public LinkedBlockingQueue getRealtimeEventNotificationQueue() { +// return realtimeEventNotificationQueue; +// } + + public FinancialServicesConfigurationService getFinancialServicesConfigurationService() { + + return configService; + } + + public void setFinancialServicesConfigurationService( + FinancialServicesConfigurationService configService) { + + this.configService = configService; + } + +// public void setRealtimeEventNotificationQueue(LinkedBlockingQueue queue) { +// this.realtimeEventNotificationQueue = queue; +// } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/AggregatedPollingResponse.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/AggregatedPollingResponse.java new file mode 100644 index 00000000..cc1d89d4 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/AggregatedPollingResponse.java @@ -0,0 +1,64 @@ +/** + * 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.service.model; + +import java.util.HashMap; +import java.util.Map; + +/** + * Default Polling Response Implementation. + */ +public class AggregatedPollingResponse { + + private Map sets = new HashMap<>(); + + //For more available parameter + private int count = 0; + + private String status; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Map getSets() { + return sets; + } + + public void setSets(Map sets) { + this.sets = sets; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public Boolean isMoreAvailable() { + return count > 0; + } + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventCreationResponse.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventCreationResponse.java new file mode 100644 index 00000000..ad1ccd5d --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventCreationResponse.java @@ -0,0 +1,55 @@ +/** + * 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.service.model; + +import org.json.JSONObject; + +/** + * This class is to pass the event creation response to the api endpoint. + */ +public class EventCreationResponse { + + private String status; + private JSONObject responseBody; + private JSONObject errorResponse; + + public JSONObject getErrorResponse() { + return errorResponse; + } + + public void setErrorResponse(JSONObject errorResponse) { + this.errorResponse = errorResponse; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public JSONObject getResponseBody() { + return responseBody; + } + + public void setResponseBody(JSONObject responseBody) { + this.responseBody = responseBody; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventPolling.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventPolling.java new file mode 100644 index 00000000..7b415809 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventPolling.java @@ -0,0 +1,86 @@ +/** + * 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.service.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Event Polling model. + */ +public class EventPolling { + + private Boolean returnImmediately = true; + private String clientId = null; + private int maxEvents = 0; + private int setsToReturn = 0; + private List ack = new ArrayList(); + private Map errors = new HashMap(); + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public Boolean getReturnImmediately() { + return returnImmediately; + } + + public void setReturnImmediately(Boolean returnImmediately) { + this.returnImmediately = returnImmediately; + } + + public int getMaxEvents() { + return maxEvents; + } + + public void setMaxEvents(int maxEvents) { + this.maxEvents = maxEvents; + } + + public int getSetsToReturn() { + return setsToReturn; + } + + public void setSetsToReturn(int setsToReturn) { + this.setsToReturn = setsToReturn; + } + + public List getAck() { + return ack; + } + + + public void setAck(String ack) { + this.ack.add(ack); + } + + public Map getErrors() { + return errors; + } + + public void setErrors(String notificationId, NotificationError errorNotification) { + this.errors.put(notificationId, errorNotification); + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventPollingResponse.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventPollingResponse.java new file mode 100644 index 00000000..5ab64a4a --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventPollingResponse.java @@ -0,0 +1,55 @@ +/** + * 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.service.model; + +import org.json.JSONObject; + +/** + * This class is used to map the Event Polling service response to the API response. + */ +public class EventPollingResponse { + + private String status; + private JSONObject responseBody; + private JSONObject errorResponse; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public JSONObject getResponseBody() { + return responseBody; + } + + public void setResponseBody(JSONObject responseBody) { + this.responseBody = responseBody; + } + + public JSONObject getErrorResponse() { + return errorResponse; + } + + public void setErrorResponse(JSONObject errorResponse) { + this.errorResponse = errorResponse; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventSubscription.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventSubscription.java new file mode 100644 index 00000000..a870be05 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventSubscription.java @@ -0,0 +1,100 @@ +/** + * 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.service.model; + +import java.util.List; + +/** + * This is the Event Subscription Model. + */ +public class EventSubscription { + + private String subscriptionId = null; + private String clientId = null; + private String callbackUrl = null; + private Long timeStamp = null; + private String specVersion = null; + private String status = null; + private List eventTypes = null; + private String requestData = null; + + public String getSubscriptionId() { + return subscriptionId; + } + + public void setSubscriptionId(String subscriptionId) { + this.subscriptionId = subscriptionId; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + + public Long getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(Long timeStamp) { + this.timeStamp = timeStamp; + } + + public String getSpecVersion() { + return specVersion; + } + + public void setSpecVersion(String specVersion) { + this.specVersion = specVersion; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public List getEventTypes() { + return eventTypes; + } + + public void setEventTypes(List eventTypes) { + this.eventTypes = eventTypes; + } + + public String getRequestData() { + return requestData; + } + + public void setRequestData(String requestData) { + this.requestData = requestData; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventSubscriptionResponse.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventSubscriptionResponse.java new file mode 100644 index 00000000..e4f727a2 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/EventSubscriptionResponse.java @@ -0,0 +1,46 @@ +/** + * 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.service.model; + +/** + * This class is used to map the Event Subscription service response to the API response. + */ +public class EventSubscriptionResponse { + + private int responseStatus; + private Object responseBody; + + + public int getResponseStatus() { + return responseStatus; + } + + public void setResponseStatus(int responseStatus) { + this.responseStatus = responseStatus; + } + + public Object getResponseBody() { + return responseBody; + } + + public void setResponseBody(Object responseBody) { + this.responseBody = responseBody; + } + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/Notification.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/Notification.java new file mode 100644 index 00000000..0c8d5157 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/Notification.java @@ -0,0 +1,71 @@ +/** + * 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.service.model; + +/** + * This is the notification model. + */ +public class Notification { + + String notificationId = null; + String clientId = null; + String resourceId = null; + String status = null; + Long updatedTimeStamp = null; + + public String getNotificationId() { + return notificationId; + } + + public void setNotificationId(String notificationId) { + this.notificationId = notificationId; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getResourceId() { + return resourceId; + } + + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Long getUpdatedTimeStamp() { + return updatedTimeStamp; + } + + public void setUpdatedTimeStamp(Long updatedTimeStamp) { + this.updatedTimeStamp = updatedTimeStamp; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/NotificationError.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/NotificationError.java new file mode 100644 index 00000000..0a9a8058 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/NotificationError.java @@ -0,0 +1,52 @@ +/** + * 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.service.model; + +/** + * The notification error model. + */ +public class NotificationError { + private String notificationId = null; + private String errorCode = null; + private String errorDescription = null; + + public String getNotificationId() { + return notificationId; + } + + public void setNotificationId(String notificationId) { + this.notificationId = notificationId; + } + + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorDescription() { + return errorDescription; + } + + public void setErrorDescription(String errorDescription) { + this.errorDescription = errorDescription; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/NotificationEvent.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/NotificationEvent.java new file mode 100644 index 00000000..09713cec --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/NotificationEvent.java @@ -0,0 +1,64 @@ +/** + * 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.service.model; + +import org.json.JSONObject; + +/** + * This is the notification event model class. + */ +public class NotificationEvent { + + private Integer eventId = null; + private String notificationId = null; + private String eventType = null; + private JSONObject eventInformation; + + public Integer getEventId() { + return eventId; + } + + public void setEventId(Integer eventId) { + this.eventId = eventId; + } + + public String getNotificationId() { + return notificationId; + } + + public void setNotificationId(String notificationId) { + this.notificationId = notificationId; + } + + public String getEventType() { + return eventType; + } + + public void setEventType(String eventType) { + this.eventType = eventType; + } + + public JSONObject getEventInformation() { + return eventInformation; + } + + public void setEventInformation(JSONObject eventInformation) { + this.eventInformation = eventInformation; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/NotificationResponse.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/NotificationResponse.java new file mode 100644 index 00000000..d34ded42 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/model/NotificationResponse.java @@ -0,0 +1,126 @@ +/** + * 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.service.model; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.JOSEException; +import org.json.JSONObject; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This is the notification response model. + */ +public class NotificationResponse { + private String iss = null; + private Long iat = null; + private String jti = null; + private String sub = null; + private String aud = null; + private String txn = null; + private Long toe = null; + private Map events = new HashMap(); + + public Long getIat() { + return iat; + } + + public void setIat(Long iat) { + this.iat = iat; + } + + public String getJti() { + return jti; + } + + public void setJti(String jti) { + this.jti = jti; + } + + public String getSub() { + return sub; + } + + public void setSub(String sub) { + this.sub = sub; + } + + public String getAud() { + return aud; + } + + public void setAud(String aud) { + this.aud = aud; + } + + public String getTxn() { + return txn; + } + + public void setTxn(String txn) { + this.txn = txn; + } + + public Long getToe() { + return toe; + } + + public void setToe(Long toe) { + this.toe = toe; + } + + public Map getEvents() { + return events; + } + + public void setEvents(List eventsList) { + + for (NotificationEvent notificationEvent : eventsList) { + this.events.put(notificationEvent.getEventType(), notificationEvent.getEventInformation()); + } + } + + public String getIss() { + return iss; + } + + public void setIss(String iss) { + this.iss = iss; + } + + /** + * This method is to convert the class to a JSONObject. + * @param notificationResponse Notification Respnse + * @return JSONObject + * @throws IOException IOException when converting the class to JSONObject + * @throws JOSEException JOSEException when converting the class to JSONObject + * @throws IdentityOAuth2Exception IdentityOAuth2Exception when converting the class to JSONObject + */ + public static JsonNode getJsonNode(NotificationResponse notificationResponse) + throws IOException, JOSEException, IdentityOAuth2Exception { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.convertValue(notificationResponse, JsonNode.class); + } + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/persistence/EventNotificationStoreInitializer.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/persistence/EventNotificationStoreInitializer.java new file mode 100644 index 00000000..4c701bc2 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/persistence/EventNotificationStoreInitializer.java @@ -0,0 +1,107 @@ +/** + * 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.service.persistence; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.financial.services.accelerator.common.persistence.JDBCPersistenceManager; +import org.wso2.financial.services.accelerator.event.notifications.service.dao.EventNotificationDAO; +import org.wso2.financial.services.accelerator.event.notifications.service.dao.EventNotificationDAOImpl; +import org.wso2.financial.services.accelerator.event.notifications.service.dao.EventSubscriptionDAO; +import org.wso2.financial.services.accelerator.event.notifications.service.dao.EventSubscriptionDAOImpl; +import org.wso2.financial.services.accelerator.event.notifications.service.dao.PostgreSqlEventNotificationDAOImpl; +import org.wso2.financial.services.accelerator.event.notifications.service.dao.PostgreSqlEventSubscriptionDAOImpl; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; +import org.wso2.financial.services.accelerator.event.notifications.service.queries.EventNotificationSqlStatements; +import org.wso2.financial.services.accelerator.event.notifications.service.queries.EventSubscriptionSqlStatements; +import org.wso2.financial.services.accelerator.event.notifications.service.queries.MSSQLEventNotificationSqlStatements; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * Initializer Class for Event Notification Service DB. + */ +public class EventNotificationStoreInitializer { + + private static Log log = LogFactory.getLog(EventNotificationStoreInitializer.class); + private static final String MYSQL = "MySQL"; + private static final String POSTGRE = "PostgreSQL"; + private static final String MSSQL = "Microsoft"; + private static final String ORACLE = "Oracle"; + private static final String H2 = "h2"; + + public static EventNotificationDAO initializeEventNotificationDAO() throws FSEventNotificationException { + + EventNotificationDAO eventNotificationDAO; + try (Connection connection = JDBCPersistenceManager.getInstance().getDBConnection()) { + String driverName = connection.getMetaData().getDriverName(); + + if (driverName.contains(MYSQL) || driverName.contains(H2)) { + eventNotificationDAO = new EventNotificationDAOImpl(new EventNotificationSqlStatements()); + } else if (driverName.contains(POSTGRE)) { + eventNotificationDAO = new PostgreSqlEventNotificationDAOImpl(new EventNotificationSqlStatements()); + } else if (driverName.contains(MSSQL)) { + eventNotificationDAO = new EventNotificationDAOImpl(new MSSQLEventNotificationSqlStatements()); + } else if (driverName.contains(ORACLE)) { + eventNotificationDAO = new EventNotificationDAOImpl(new EventNotificationSqlStatements()); + } else { + throw new FSEventNotificationException("Unhandled DB driver: " + driverName + " detected"); + } + + } catch (SQLException e) { + throw new FSEventNotificationException("Error while getting the database connection : ", e); + } + return eventNotificationDAO; + } + + public static EventNotificationDAO getEventNotificationDAO() throws FSEventNotificationException { + + return initializeEventNotificationDAO(); + } + + public static EventSubscriptionDAO initializeSubscriptionDAO() throws FSEventNotificationException { + + EventSubscriptionDAO eventSubscriptionDao; + try (Connection connection = JDBCPersistenceManager.getInstance().getDBConnection()) { + String driverName = connection.getMetaData().getDriverName(); + + if (driverName.contains(MYSQL) || driverName.contains(H2)) { + eventSubscriptionDao = new EventSubscriptionDAOImpl(new EventSubscriptionSqlStatements()); + } else if (driverName.contains(POSTGRE)) { + eventSubscriptionDao = new PostgreSqlEventSubscriptionDAOImpl(new EventSubscriptionSqlStatements()); + } else if (driverName.contains(MSSQL)) { + eventSubscriptionDao = new EventSubscriptionDAOImpl(new EventSubscriptionSqlStatements()); + } else if (driverName.contains(ORACLE)) { + eventSubscriptionDao = new EventSubscriptionDAOImpl(new EventSubscriptionSqlStatements()); + } else { + throw new FSEventNotificationException("Unhandled DB driver: " + driverName + " detected"); + } + } catch (SQLException e) { + throw new FSEventNotificationException("Error while getting the database connection : ", e); + } + + return eventSubscriptionDao; + } + + public static EventSubscriptionDAO getEventSubscriptionDAO() throws FSEventNotificationException { + + return initializeSubscriptionDAO(); + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/queries/EventNotificationSqlStatements.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/queries/EventNotificationSqlStatements.java new file mode 100644 index 00000000..6dfe0ae5 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/queries/EventNotificationSqlStatements.java @@ -0,0 +1,70 @@ +/** + * 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.service.queries; + +/** + * SQL queries to store and retrieve event notifications. + */ +public class EventNotificationSqlStatements { + + public String getStoreNotification() { + + return "INSERT INTO FS_NOTIFICATION (NOTIFICATION_ID, CLIENT_ID, RESOURCE_ID, STATUS) VALUES (?,?,?,?)"; + } + + public String getStoreNotificationEvents() { + + return "INSERT INTO FS_NOTIFICATION_EVENT (NOTIFICATION_ID, EVENT_TYPE, EVENT_INFO) VALUES (?,?,?)"; + } + + public String getEventsByNotificationIdQuery() { + + return "SELECT * FROM FS_NOTIFICATION_EVENT WHERE NOTIFICATION_ID = ?"; + } + + public String getMaxNotificationsQuery() { + + return "SELECT * FROM FS_NOTIFICATION WHERE CLIENT_ID = ? AND STATUS = ? LIMIT ?"; + } + + public String getNotificationsCountQuery() { + + return "SELECT COUNT(*) AS NOTIFICATION_COUNT FROM FS_NOTIFICATION WHERE CLIENT_ID = ? AND STATUS = ?"; + } + + public String storeErrorNotificationQuery() { + + return "INSERT INTO FS_NOTIFICATION_ERROR (NOTIFICATION_ID, ERROR_CODE, DESCRIPTION) VALUES (?,?,?)"; + } + + public String updateNotificationStatusQueryById() { + + return "UPDATE FS_NOTIFICATION SET STATUS = ?, UPDATED_TIMESTAMP= ? WHERE NOTIFICATION_ID = ?"; + } + + public String getNotificationByNotificationId() { + + return "SELECT NOTIFICATION_ID, STATUS FROM FS_NOTIFICATION WHERE NOTIFICATION_ID = ?"; + } + + public String getNotificationsByState() { + + return "SELECT * FROM FS_NOTIFICATION WHERE STATUS = ?"; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/queries/EventSubscriptionSqlStatements.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/queries/EventSubscriptionSqlStatements.java new file mode 100644 index 00000000..818424bb --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/queries/EventSubscriptionSqlStatements.java @@ -0,0 +1,71 @@ +/** + * 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.service.queries; + +/** + * SQL queries to store, retrieve, update and delete event notification subscriptions. + */ +public class EventSubscriptionSqlStatements { + + public String storeEventSubscriptionQuery() { + return "INSERT INTO FS_NOTIFICATION_SUBSCRIPTION (SUBSCRIPTION_ID, CLIENT_ID, CALLBACK_URL, TIMESTAMP, " + + "SPEC_VERSION, STATUS, REQUEST) VALUES (?,?,?,?,?,?,?)"; + } + + public String storeSubscribedEventTypesQuery() { + return "INSERT INTO FS_NOTIFICATION_SUBSCRIBED_EVENTS (SUBSCRIPTION_ID, EVENT_TYPE) VALUES (?,?)"; + } + + public String getEventSubscriptionBySubscriptionIdQuery() { + return "SELECT ns.SUBSCRIPTION_ID, ns.CLIENT_ID, ns.REQUEST, ns.CALLBACK_URL, ns.TIMESTAMP, ns.SPEC_VERSION, " + + "ns.STATUS, nse.EVENT_TYPE FROM FS_NOTIFICATION_SUBSCRIPTION ns LEFT JOIN " + + "FS_NOTIFICATION_SUBSCRIBED_EVENTS nse ON ns.SUBSCRIPTION_ID = nse.SUBSCRIPTION_ID WHERE " + + "ns.SUBSCRIPTION_ID = ? AND ns.STATUS = 'CREATED'"; + } + + public String getEventSubscriptionsByClientIdQuery() { + return "SELECT ns.SUBSCRIPTION_ID, ns.CLIENT_ID, ns.REQUEST, ns.CALLBACK_URL, ns.TIMESTAMP, ns.SPEC_VERSION, " + + "ns.STATUS, nse.EVENT_TYPE FROM FS_NOTIFICATION_SUBSCRIPTION ns LEFT JOIN " + + "FS_NOTIFICATION_SUBSCRIBED_EVENTS nse ON ns.SUBSCRIPTION_ID = nse.SUBSCRIPTION_ID WHERE " + + "ns.CLIENT_ID = ? AND ns.STATUS = 'CREATED'"; + } + + public String getEventSubscriptionsByEventTypeQuery() { + return "SELECT ns.SUBSCRIPTION_ID, ns.CLIENT_ID, ns.REQUEST, ns.CALLBACK_URL, ns.TIMESTAMP, ns.SPEC_VERSION, " + + "ns.STATUS, nse.EVENT_TYPE FROM FS_NOTIFICATION_SUBSCRIPTION ns LEFT JOIN " + + "FS_NOTIFICATION_SUBSCRIBED_EVENTS nse ON ns.SUBSCRIPTION_ID = nse.SUBSCRIPTION_ID WHERE " + + "ns.SUBSCRIPTION_ID IN (SELECT ns.SUBSCRIPTION_ID FROM FS_NOTIFICATION_SUBSCRIPTION ns LEFT " + + "JOIN FS_NOTIFICATION_SUBSCRIBED_EVENTS nse ON ns.SUBSCRIPTION_ID = nse.SUBSCRIPTION_ID WHERE " + + "nse.EVENT_TYPE = ? AND ns.STATUS = 'CREATED')"; + } + + public String updateEventSubscriptionQuery() { + return "UPDATE FS_NOTIFICATION_SUBSCRIPTION SET CALLBACK_URL = ?, TIMESTAMP = ?, REQUEST = ?" + + "WHERE SUBSCRIPTION_ID = ?"; + } + + public String updateEventSubscriptionStatusQuery() { + return "UPDATE FS_NOTIFICATION_SUBSCRIPTION SET STATUS = ? WHERE SUBSCRIPTION_ID = ? AND STATUS = 'CREATED'"; + } + + public String deleteSubscribedEventTypesQuery() { + return "DELETE FROM FS_NOTIFICATION_SUBSCRIBED_EVENTS WHERE SUBSCRIPTION_ID = ?"; + } + +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/queries/MSSQLEventNotificationSqlStatements.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/queries/MSSQLEventNotificationSqlStatements.java new file mode 100644 index 00000000..ba4e35ef --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/queries/MSSQLEventNotificationSqlStatements.java @@ -0,0 +1,32 @@ +/** + * 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.service.queries; + +/** + * MSSQL Queries for Event Notifications. + */ +public class MSSQLEventNotificationSqlStatements extends EventNotificationSqlStatements { + + @Override + public String getMaxNotificationsQuery() { + + return "SELECT * FROM FS_NOTIFICATION WHERE CLIENT_ID = ? AND STATUS = ? ORDER BY NOTIFICATION_ID " + + "OFFSET 0 ROWS FETCH NEXT ? ROWS ONLY"; + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/util/EventNotificationServiceUtil.java b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/util/EventNotificationServiceUtil.java new file mode 100644 index 00000000..b3916f14 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/java/org/wso2/financial/services/accelerator/event/notifications/service/util/EventNotificationServiceUtil.java @@ -0,0 +1,144 @@ +/** + * 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.service.util; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONException; +import org.json.JSONObject; +import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.util.OAuth2Util; +import org.wso2.financial.services.accelerator.common.config.FinancialServicesConfigParser; +import org.wso2.financial.services.accelerator.common.util.FinancialServicesUtils; +import org.wso2.financial.services.accelerator.common.util.Generated; +import org.wso2.financial.services.accelerator.consent.mgt.service.impl.ConsentCoreServiceImpl; +import org.wso2.financial.services.accelerator.event.notifications.service.EventNotificationGenerator; +import org.wso2.financial.services.accelerator.event.notifications.service.constants.EventNotificationConstants; +import org.wso2.financial.services.accelerator.event.notifications.service.exception.FSEventNotificationException; + +import java.util.Optional; + +/** + * Default event notification validations. + */ +public class EventNotificationServiceUtil { + + private static final Log log = LogFactory.getLog(EventNotificationServiceUtil.class); + private static volatile ConsentCoreServiceImpl consentCoreService; + + /** + * This method is used to send the polling generator as per config. + * + * @return EventNotificationGenerator + */ + public static EventNotificationGenerator getEventNotificationGenerator() { + + return (EventNotificationGenerator) + FinancialServicesUtils.getClassInstanceFromFQN(FinancialServicesConfigParser.getInstance() + .getEventNotificationGenerator()); + } + + /** + * This method is used to send the default realtime event notification request generator. + * + * @return RealtimeEventNotificationRequestGenerator + */ + //TODO +// public static RealtimeEventNotificationRequestGenerator getRealtimeEventNotificationRequestGenerator() { +// +// RealtimeEventNotificationRequestGenerator realtimeEventNotificationRequestGenerator = +// (RealtimeEventNotificationRequestGenerator) FinancialServicesUtils +// .getClassInstanceFromFQN(FinancialServicesConfigParser.getInstance(). +// getRealtimeEventNotificationRequestGenerator()); +// return realtimeEventNotificationRequestGenerator; +// } + + /** + * Method to get event JSON from eventInformation payload string. + * @param eventInformation String event Information + * @return JSONObject converted event json + * @throws JSONException Exception when parsing event information + */ + public static JSONObject getEventJSONFromString(String eventInformation) throws JSONException { + + return new JSONObject(eventInformation); + } + + /** + * Validate if the client ID is existing. + * @param clientId client ID of the TPP + * @throws FSEventNotificationException Exception when validating client ID + */ + @Generated(message = "Excluded since this needs OAuth2Util service provider") + public static void validateClientId(String clientId) throws FSEventNotificationException { + + if (StringUtils.isNotEmpty(clientId)) { + Optional serviceProvider; + try { + serviceProvider = Optional.ofNullable(OAuth2Util.getServiceProvider(clientId)); + if (!serviceProvider.isPresent()) { + log.error(EventNotificationConstants.INVALID_CLIENT_ID); + throw new FSEventNotificationException(EventNotificationConstants.INVALID_CLIENT_ID); + } + } catch (IdentityOAuth2Exception e) { + log.error(EventNotificationConstants.INVALID_CLIENT_ID, e); + throw new FSEventNotificationException(EventNotificationConstants.INVALID_CLIENT_ID); + } + } + } + + @Generated(message = "Creating a single instance for ConsentCoreService") + public static synchronized ConsentCoreServiceImpl getConsentCoreServiceImpl() { + if (consentCoreService == null) { + synchronized (ConsentCoreServiceImpl.class) { + if (consentCoreService == null) { + consentCoreService = new ConsentCoreServiceImpl(); + } + } + } + return consentCoreService; + } + + /** + * Get the callback URL of the TPP from the Subscription Object. + * + * @param clientID client ID of the TPP + * @return callback URL of the TPP + */ + public static String getCallbackURL(String clientID) { + + return "http://localhost:8080/sample-tpp-server"; + } + + /** + * Method to map Event subscription Service error to API response. + * + * @param error Error code + * @param errorDescription Error description + * @return String error response + */ + public static String getErrorDTO(String error, String errorDescription) { + JSONObject eventNotificationError = new JSONObject(); + eventNotificationError.put(EventNotificationConstants.ERROR_FIELD, error); + eventNotificationError.put(EventNotificationConstants.ERROR_DESCRIPTION_FIELD, errorDescription); + return eventNotificationError.toString(); + } +} diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/resources/findbugs-exclude.xml b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/resources/findbugs-exclude.xml new file mode 100644 index 00000000..eebf9f61 --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/resources/findbugs-exclude.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/resources/findbugs-include.xml b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/resources/findbugs-include.xml new file mode 100644 index 00000000..8932a22e --- /dev/null +++ b/financial-services-accelerator/components/org.wso2.financial.services.accelerator.event.notifications.service/src/main/resources/findbugs-include.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/financial-services-accelerator/pom.xml b/financial-services-accelerator/pom.xml index ba196537..37a3dea7 100644 --- a/financial-services-accelerator/pom.xml +++ b/financial-services-accelerator/pom.xml @@ -38,6 +38,7 @@ components/org.wso2.financial.services.accelerator.consent.mgt.extensions components/org.wso2.financial.services.accelerator.identity.extensions components/org.wso2.financial.services.accelerator.gateway + components/org.wso2.financial.services.accelerator.event.notifications.service 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.demo.backend diff --git a/pom.xml b/pom.xml index 65bdd97f..07ea9463 100644 --- a/pom.xml +++ b/pom.xml @@ -388,6 +388,16 @@ jackson-databind ${jackson.databinding.version} + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.databinding.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.databinding.version} + org.springframework spring-web @@ -453,6 +463,11 @@ jjwt ${jjwt.version} + + org.quartz-scheduler + quartz + ${quartz.version} + org.wso2.carbon @@ -516,6 +531,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 @@ -591,9 +616,9 @@ 1.6.1 2.1.1 1.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 @@ -603,6 +628,7 @@ 1.2.5 9.0.11 2.0.1.Final + 2.3.2 2.1.22.wso2v1 0.9.1