You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ar...@apache.org on 2022/12/23 11:16:42 UTC
[fineract] branch develop updated: FINERACT-1734-Create-Custom-Business-Event
This is an automated email from the ASF dual-hosted git repository.
arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new d3dcc760e FINERACT-1734-Create-Custom-Business-Event
d3dcc760e is described below
commit d3dcc760e27999a8bc57da413402d05d12edddfd
Author: Ruchi Dhamankar <ru...@gmail.com>
AuthorDate: Fri Dec 23 15:23:03 2022 +0530
FINERACT-1734-Create-Custom-Business-Event
---
custom/acme/event/externalevent/build.gradle | 25 ++++++++++++
.../acme/event/externalevent/dependencies.gradle | 23 +++++++++++
.../AcmeExternalEventSourceProviderConfig.java | 35 ++++++++++++++++
.../event/externalevent/AcmeLoanExternalEvent.java | 36 +++++++++++++++++
.../0001_acme_external_event_configuration.xml | 16 +++-----
custom/acme/event/starter/build.gradle | 25 ++++++++++++
custom/acme/event/starter/dependencies.gradle | 23 +++++++++++
.../event/starter/AcmeEventAutoConfiguration.java | 27 +++++++++++++
.../src/main/resources/META-INF/spring.factories | 2 +
.../migration/TenantDatabaseUpgradeService.java | 46 +++++++++++-----------
...xternalEventConfigurationValidationService.java | 16 +++++++-
.../validation/ExternalEventSourceData.java | 29 ++++++++++++++
.../validation/ExternalEventSourceProvider.java | 26 ++++++++++++
.../ExternalEventSourceProviderConfig.java | 36 +++++++++++++++++
.../validation/ExternalEventSourceService.java | 39 ++++++++++++++++++
.../SimpleExternalEventSourceProvider.java | 36 +++++++++++++++++
.../resources/db/changelog/db.changelog-master.xml | 2 +-
.../core/LiquibaseStepDefinitions.java | 3 ++
...nalEventConfigurationValidationServiceTest.java | 15 +++++--
19 files changed, 421 insertions(+), 39 deletions(-)
diff --git a/custom/acme/event/externalevent/build.gradle b/custom/acme/event/externalevent/build.gradle
new file mode 100644
index 000000000..bb703fb8a
--- /dev/null
+++ b/custom/acme/event/externalevent/build.gradle
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.
+ */
+description = 'ACME Corp.: Fineract external events'
+
+group = 'com.acme.fineract.event'
+
+archivesBaseName = 'acme-fineract-event-externalevent'
+
+apply from: 'dependencies.gradle'
diff --git a/custom/acme/event/externalevent/dependencies.gradle b/custom/acme/event/externalevent/dependencies.gradle
new file mode 100644
index 000000000..364f7d772
--- /dev/null
+++ b/custom/acme/event/externalevent/dependencies.gradle
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.
+ */
+
+dependencies {
+ implementation(project(':fineract-provider'))
+ implementation('org.springframework.boot:spring-boot-starter-data-jpa')
+}
diff --git a/custom/acme/event/externalevent/src/main/java/com/acme/fineract/event/externalevent/AcmeExternalEventSourceProviderConfig.java b/custom/acme/event/externalevent/src/main/java/com/acme/fineract/event/externalevent/AcmeExternalEventSourceProviderConfig.java
new file mode 100644
index 000000000..8d98d814b
--- /dev/null
+++ b/custom/acme/event/externalevent/src/main/java/com/acme/fineract/event/externalevent/AcmeExternalEventSourceProviderConfig.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 com.acme.fineract.event.externalevent;
+
+import java.util.List;
+import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventSourceData;
+import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventSourceProvider;
+import org.apache.fineract.infrastructure.event.external.service.validation.SimpleExternalEventSourceProvider;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class AcmeExternalEventSourceProviderConfig {
+
+ @Bean
+ public ExternalEventSourceProvider acmeEventSourceProvider() {
+ return new SimpleExternalEventSourceProvider(List.of(new ExternalEventSourceData("com.acme.fineract.event.externalevent")));
+ }
+}
diff --git a/custom/acme/event/externalevent/src/main/java/com/acme/fineract/event/externalevent/AcmeLoanExternalEvent.java b/custom/acme/event/externalevent/src/main/java/com/acme/fineract/event/externalevent/AcmeLoanExternalEvent.java
new file mode 100644
index 000000000..80d45a9ce
--- /dev/null
+++ b/custom/acme/event/externalevent/src/main/java/com/acme/fineract/event/externalevent/AcmeLoanExternalEvent.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 com.acme.fineract.event.externalevent;
+
+import org.apache.fineract.infrastructure.event.business.domain.loan.LoanBusinessEvent;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+
+public class AcmeLoanExternalEvent extends LoanBusinessEvent {
+
+ private static final String TYPE = "AcmeLoanExternalEvent";
+
+ public AcmeLoanExternalEvent(Loan value) {
+ super(value);
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+}
diff --git a/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml b/custom/acme/event/externalevent/src/main/resources/db/custom-changelog/0001_acme_external_event_configuration.xml
similarity index 54%
copy from fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml
copy to custom/acme/event/externalevent/src/main/resources/db/custom-changelog/0001_acme_external_event_configuration.xml
index 1e3d3e114..05a143eb7 100644
--- a/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml
+++ b/custom/acme/event/externalevent/src/main/resources/db/custom-changelog/0001_acme_external_event_configuration.xml
@@ -22,14 +22,10 @@
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
- <property name="current_date" value="CURDATE()" context="mysql"/>
- <property name="current_date" value="CURRENT_DATE" context="postgresql"/>
- <property name="current_datetime" value="NOW()"/>
- <property name="uuid" value="uuid()" context="mysql"/>
- <property name="uuid" value="uuid_generate_v4()" context="postgresql"/>
- <include file="tenant-store/initial-switch-changelog-tenant-store.xml" relativeToChangelogFile="true" context="tenant_store_db AND initial_switch"/>
- <include file="tenant-store/changelog-tenant-store.xml" relativeToChangelogFile="true" context="tenant_store_db AND !initial_switch"/>
- <include file="tenant/initial-switch-changelog-tenant.xml" relativeToChangelogFile="true" context="tenant_db AND initial_switch"/>
- <include file="tenant/changelog-tenant.xml" relativeToChangelogFile="true" context="tenant_db AND !initial_switch"/>
- <includeAll path="db/custom-changelog" errorIfMissingOrEmpty="false" context="tenant_db" />
+ <changeSet author="acme" id="1">
+ <insert tableName="m_external_event_configuration">
+ <column name="type" value="AcmeLoanExternalEvent"/>
+ <column name="enabled" valueBoolean="false"/>
+ </insert>
+ </changeSet>
</databaseChangeLog>
diff --git a/custom/acme/event/starter/build.gradle b/custom/acme/event/starter/build.gradle
new file mode 100644
index 000000000..314a45cf4
--- /dev/null
+++ b/custom/acme/event/starter/build.gradle
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.
+ */
+description = 'ACME Corp.: Fineract Event Starter'
+
+group = 'com.acme.fineract.event'
+
+archivesBaseName = 'acme-fineract-event-starter'
+
+apply from: 'dependencies.gradle'
diff --git a/custom/acme/event/starter/dependencies.gradle b/custom/acme/event/starter/dependencies.gradle
new file mode 100644
index 000000000..30b090b9f
--- /dev/null
+++ b/custom/acme/event/starter/dependencies.gradle
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.
+ */
+
+dependencies {
+ implementation(project(':fineract-provider'))
+ implementation('org.springframework.boot:spring-boot-starter')
+}
diff --git a/custom/acme/event/starter/src/main/java/com/acme/fineract/event/starter/AcmeEventAutoConfiguration.java b/custom/acme/event/starter/src/main/java/com/acme/fineract/event/starter/AcmeEventAutoConfiguration.java
new file mode 100644
index 000000000..ea8d65d74
--- /dev/null
+++ b/custom/acme/event/starter/src/main/java/com/acme/fineract/event/starter/AcmeEventAutoConfiguration.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 com.acme.fineract.event.starter;
+
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ComponentScans;
+
+@AutoConfiguration
+@ComponentScans({ @ComponentScan("com.acme.fineract.event.externalevent") })
+public class AcmeEventAutoConfiguration {}
diff --git a/custom/acme/event/starter/src/main/resources/META-INF/spring.factories b/custom/acme/event/starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..28d54193a
--- /dev/null
+++ b/custom/acme/event/starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.acme.fineract.event.starter.AcmeEventAutoConfiguration
\ No newline at end of file
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDatabaseUpgradeService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDatabaseUpgradeService.java
index dd3a974ce..1faf5b7e2 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDatabaseUpgradeService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDatabaseUpgradeService.java
@@ -25,11 +25,10 @@ import java.util.function.Function;
import javax.sql.DataSource;
import liquibase.exception.LiquibaseException;
import liquibase.integration.spring.SpringLiquibase;
+import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -39,12 +38,13 @@ import org.springframework.stereotype.Service;
* A service that picks up on tenants that are configured to auto-update their specific schema on application startup.
*/
@Service
+@Slf4j
public class TenantDatabaseUpgradeService implements InitializingBean {
- private static final Logger LOG = LoggerFactory.getLogger(TenantDatabaseUpgradeService.class);
private static final String TENANT_STORE_DB_CONTEXT = "tenant_store_db";
private static final String INITIAL_SWITCH_CONTEXT = "initial_switch";
private static final String TENANT_DB_CONTEXT = "tenant_db";
+ private static final String CUSTOM_CHANGELOG_CONTEXT = "custom_changelog";
private final TenantDetailsService tenantDetailsService;
private final DataSource tenantDataSource;
@@ -69,9 +69,9 @@ public class TenantDatabaseUpgradeService implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
if (databaseStateVerifier.isLiquibaseDisabled() || !fineractProperties.getMode().isWriteEnabled()) {
- LOG.warn("Liquibase is disabled. Not upgrading any database.");
+ log.warn("Liquibase is disabled. Not upgrading any database.");
if (!fineractProperties.getMode().isWriteEnabled()) {
- LOG.warn("Liquibase is disabled because the current instance is configured as a non-write Fineract instance");
+ log.warn("Liquibase is disabled because the current instance is configured as a non-write Fineract instance");
}
return;
}
@@ -84,7 +84,7 @@ public class TenantDatabaseUpgradeService implements InitializingBean {
}
private void upgradeTenantStore() throws LiquibaseException {
- LOG.warn("Upgrading tenant store DB at {}:{}", fineractProperties.getTenant().getHost(), fineractProperties.getTenant().getPort());
+ log.warn("Upgrading tenant store DB at {}:{}", fineractProperties.getTenant().getHost(), fineractProperties.getTenant().getPort());
logTenantStoreDetails();
if (databaseStateVerifier.isFirstLiquibaseMigration(tenantDataSource)) {
ExtendedSpringLiquibase liquibase = liquibaseFactory.create(tenantDataSource, TENANT_STORE_DB_CONTEXT, INITIAL_SWITCH_CONTEXT);
@@ -93,32 +93,32 @@ public class TenantDatabaseUpgradeService implements InitializingBean {
}
SpringLiquibase liquibase = liquibaseFactory.create(tenantDataSource, TENANT_STORE_DB_CONTEXT);
liquibase.afterPropertiesSet();
- LOG.warn("Tenant store upgrade finished");
+ log.warn("Tenant store upgrade finished");
}
private void logTenantStoreDetails() {
- LOG.info("- fineract.tenant.username: {}", fineractProperties.getTenant().getUsername());
- LOG.info("- fineract.tenant.password: ****");
- LOG.info("- fineract.tenant.parameters: {}", fineractProperties.getTenant().getParameters());
- LOG.info("- fineract.tenant.timezone: {}", fineractProperties.getTenant().getTimezone());
- LOG.info("- fineract.tenant.description: {}", fineractProperties.getTenant().getDescription());
- LOG.info("- fineract.tenant.identifier: {}", fineractProperties.getTenant().getIdentifier());
- LOG.info("- fineract.tenant.name: {}", fineractProperties.getTenant().getName());
+ log.info("- fineract.tenant.username: {}", fineractProperties.getTenant().getUsername());
+ log.info("- fineract.tenant.password: ****");
+ log.info("- fineract.tenant.parameters: {}", fineractProperties.getTenant().getParameters());
+ log.info("- fineract.tenant.timezone: {}", fineractProperties.getTenant().getTimezone());
+ log.info("- fineract.tenant.description: {}", fineractProperties.getTenant().getDescription());
+ log.info("- fineract.tenant.identifier: {}", fineractProperties.getTenant().getIdentifier());
+ log.info("- fineract.tenant.name: {}", fineractProperties.getTenant().getName());
}
private void upgradeIndividualTenants() throws LiquibaseException {
- LOG.warn("Upgrading all tenants");
+ log.warn("Upgrading all tenants");
List<FineractPlatformTenant> tenants = tenantDetailsService.findAllTenants();
if (isNotEmpty(tenants)) {
for (FineractPlatformTenant tenant : tenants) {
upgradeIndividualTenant(tenant);
}
}
- LOG.warn("Tenant upgrades have finished");
+ log.warn("Tenant upgrades have finished");
}
private void upgradeIndividualTenant(FineractPlatformTenant tenant) throws LiquibaseException {
- LOG.info("Upgrade for tenant {} has started", tenant.getTenantIdentifier());
+ log.info("Upgrade for tenant {} has started", tenant.getTenantIdentifier());
DataSource tenantDataSource = tenantDataSourceFactory.create(tenant);
if (databaseStateVerifier.isFirstLiquibaseMigration(tenantDataSource)) {
ExtendedSpringLiquibase liquibase = liquibaseFactory.create(tenantDataSource, TENANT_DB_CONTEXT, INITIAL_SWITCH_CONTEXT);
@@ -127,20 +127,22 @@ public class TenantDatabaseUpgradeService implements InitializingBean {
}
SpringLiquibase tenantLiquibase = liquibaseFactory.create(tenantDataSource, TENANT_DB_CONTEXT);
tenantLiquibase.afterPropertiesSet();
- LOG.info("Upgrade for tenant {} has finished", tenant.getTenantIdentifier());
+ SpringLiquibase customChangelogLiquibase = liquibaseFactory.create(tenantDataSource, TENANT_DB_CONTEXT, CUSTOM_CHANGELOG_CONTEXT);
+ customChangelogLiquibase.afterPropertiesSet();
+ log.info("Upgrade for tenant {} has finished", tenant.getTenantIdentifier());
}
private void applyInitialLiquibase(DataSource dataSource, ExtendedSpringLiquibase liquibase, String id,
Function<DataSource, Boolean> isUpgradableFn) throws LiquibaseException {
if (databaseStateVerifier.isFlywayPresent(dataSource)) {
if (isUpgradableFn.apply(dataSource)) {
- LOG.warn("Cannot proceed with upgrading database {}", id);
- LOG.warn("It seems the database doesn't have the latest schema changes applied until the 1.6 release");
+ log.warn("Cannot proceed with upgrading database {}", id);
+ log.warn("It seems the database doesn't have the latest schema changes applied until the 1.6 release");
throw new SchemaUpgradeNeededException("Make sure to upgrade to Fineract 1.6 first and then to a newer version");
}
- LOG.warn("This is the first Liquibase migration for {}. We'll sync the changelog for you and then apply everything else", id);
+ log.warn("This is the first Liquibase migration for {}. We'll sync the changelog for you and then apply everything else", id);
liquibase.changeLogSync();
- LOG.warn("Liquibase changelog sync is complete");
+ log.warn("Liquibase changelog sync is complete");
} else {
liquibase.afterPropertiesSet();
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java
index 68dcd6cc9..b3c7efc69 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java
@@ -27,10 +27,12 @@ import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.event.business.domain.BulkBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
import org.apache.fineract.infrastructure.event.external.exception.ExternalEventConfigurationNotFoundException;
+import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventSourceService;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -41,11 +43,11 @@ import org.springframework.stereotype.Service;
@Service
public class ExternalEventConfigurationValidationService implements InitializingBean {
- private static final String EXTERNAL_EVENT_CLASSES_BASE_PACKAGE = "org.apache.fineract.infrastructure.event.business.domain";
private static final String EXTERNAL_EVENT_BUSINESS_INTERFACE = BusinessEvent.class.getName();
private static final String BULK_BUSINESS_EVENT = BulkBusinessEvent.class.getName();
private final TenantDetailsService tenantDetailsService;
private final JdbcTemplateFactory jdbcTemplateFactory;
+ private final ExternalEventSourceService externalEventSourceService;
@Override
public void afterPropertiesSet() throws Exception {
@@ -67,6 +69,10 @@ public class ExternalEventConfigurationValidationService implements Initializing
throws ExternalEventConfigurationNotFoundException {
log.info("Validating external event configuration for {}", tenant.getTenantIdentifier());
List<String> eventConfigurations = getExternalEventConfigurationsForTenant(tenant);
+ if (log.isDebugEnabled()) {
+ log.debug("Missing from eventClasses: {}", CollectionUtils.subtract(eventClasses, eventConfigurations));
+ log.debug("Missing from eventConfigurations: {}", CollectionUtils.subtract(eventConfigurations, eventClasses));
+ }
if (eventClasses.size() != eventConfigurations.size()) {
throw new ExternalEventConfigurationNotFoundException();
@@ -88,7 +94,13 @@ public class ExternalEventConfigurationValidationService implements Initializing
}
private List<String> getAllEventClasses() {
- try (ScanResult scanResult = new ClassGraph().enableAllInfo().acceptPackages(EXTERNAL_EVENT_CLASSES_BASE_PACKAGE).scan()) {
+ List<String> sourcePackages = externalEventSourceService.getSourcePackages();
+ if (log.isDebugEnabled()) {
+ log.debug("Packages {}", sourcePackages);
+ }
+ String[] sourcePackagesForScan = new String[sourcePackages.size()];
+ try (ScanResult scanResult = new ClassGraph().enableAllInfo().acceptPackages(sourcePackages.toArray(sourcePackagesForScan))
+ .scan()) {
ClassInfoList businessEventClasses = scanResult.getClassesImplementing(EXTERNAL_EVENT_BUSINESS_INTERFACE)
.filter(classInfo -> (!classInfo.isInterface() && !classInfo.isAbstract()
&& !classInfo.getName().equalsIgnoreCase(BULK_BUSINESS_EVENT)));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceData.java
new file mode 100644
index 000000000..575eb0133
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceData.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.fineract.infrastructure.event.external.service.validation;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class ExternalEventSourceData {
+
+ private final String sourcePackage;
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceProvider.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceProvider.java
new file mode 100644
index 000000000..7da3e67dc
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceProvider.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.fineract.infrastructure.event.external.service.validation;
+
+import java.util.Set;
+
+public interface ExternalEventSourceProvider {
+
+ Set<ExternalEventSourceData> provide();
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceProviderConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceProviderConfig.java
new file mode 100644
index 000000000..b76ac648f
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceProviderConfig.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.fineract.infrastructure.event.external.service.validation;
+
+import java.util.Arrays;
+import java.util.List;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ExternalEventSourceProviderConfig {
+
+ private static final String EXTERNAL_EVENT_CLASSES_BASE_PACKAGE = "org.apache.fineract.infrastructure.event.business.domain";
+
+ @Bean
+ public ExternalEventSourceProvider fineractExternalEventSourceProvider() {
+ List<ExternalEventSourceData> sourcePackages = Arrays.asList(new ExternalEventSourceData(EXTERNAL_EVENT_CLASSES_BASE_PACKAGE));
+ return new SimpleExternalEventSourceProvider(sourcePackages);
+ }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceService.java
new file mode 100644
index 000000000..d4f1cb106
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/ExternalEventSourceService.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.fineract.infrastructure.event.external.service.validation;
+
+import static java.util.stream.Collectors.toList;
+
+import java.util.Collection;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class ExternalEventSourceService {
+
+ private final Collection<ExternalEventSourceProvider> providers;
+
+ public List<String> getSourcePackages() {
+ return providers.stream().map(ExternalEventSourceProvider::provide).flatMap(Collection::stream)
+ .map(source -> source.getSourcePackage()).collect(toList());
+ }
+
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/SimpleExternalEventSourceProvider.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/SimpleExternalEventSourceProvider.java
new file mode 100644
index 000000000..f23864188
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/validation/SimpleExternalEventSourceProvider.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.fineract.infrastructure.event.external.service.validation;
+
+import java.util.Collection;
+import java.util.Set;
+
+public class SimpleExternalEventSourceProvider implements ExternalEventSourceProvider {
+
+ private final Set<ExternalEventSourceData> sourcePackages;
+
+ public SimpleExternalEventSourceProvider(Collection<ExternalEventSourceData> sourcePackages) {
+ this.sourcePackages = Set.copyOf(sourcePackages);
+ }
+
+ @Override
+ public Set<ExternalEventSourceData> provide() {
+ return sourcePackages;
+ }
+}
diff --git a/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml b/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml
index 1e3d3e114..6d7a0bd16 100644
--- a/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml
+++ b/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml
@@ -31,5 +31,5 @@
<include file="tenant-store/changelog-tenant-store.xml" relativeToChangelogFile="true" context="tenant_store_db AND !initial_switch"/>
<include file="tenant/initial-switch-changelog-tenant.xml" relativeToChangelogFile="true" context="tenant_db AND initial_switch"/>
<include file="tenant/changelog-tenant.xml" relativeToChangelogFile="true" context="tenant_db AND !initial_switch"/>
- <includeAll path="db/custom-changelog" errorIfMissingOrEmpty="false" context="tenant_db" />
+ <includeAll path="db/custom-changelog" errorIfMissingOrEmpty="false" context="tenant_db AND custom_changelog" />
</databaseChangeLog>
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java
index b55fdc32f..be2143c33 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java
@@ -54,6 +54,7 @@ public class LiquibaseStepDefinitions implements En {
private ExtendedSpringLiquibase tenantStoreLiquibase;
private ExtendedSpringLiquibase initialTenantLiquibase;
private ExtendedSpringLiquibase tenantLiquibase;
+ private ExtendedSpringLiquibase customChangeLogLiquibase;
private FineractPlatformTenant defaultTenant;
private DataSource tenantStoreDataSource;
private TenantDatabaseUpgradeService tenantDatabaseUpgradeService;
@@ -158,6 +159,7 @@ public class LiquibaseStepDefinitions implements En {
initialTenantLiquibase = mock(ExtendedSpringLiquibase.class);
tenantLiquibase = mock(ExtendedSpringLiquibase.class);
+ customChangeLogLiquibase = mock(ExtendedSpringLiquibase.class);
initialTenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
tenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
@@ -171,6 +173,7 @@ public class LiquibaseStepDefinitions implements En {
given(tenantDataSourceFactory.create(defaultTenant)).willReturn(defaultTenantDataSource);
given(liquibaseFactory.create(defaultTenantDataSource, "tenant_db", "initial_switch")).willReturn(initialTenantLiquibase);
given(liquibaseFactory.create(defaultTenantDataSource, "tenant_db")).willReturn(tenantLiquibase);
+ given(liquibaseFactory.create(defaultTenantDataSource, "tenant_db", "custom_changelog")).willReturn(customChangeLogLiquibase);
tenantDatabaseUpgradeService = new TenantDatabaseUpgradeService(tenantDetailsService, tenantStoreDataSource, fineractProperties,
databaseStateVerifier, liquibaseFactory, tenantDataSourceFactory);
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
index d17e90d42..abf792af6 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
@@ -32,6 +32,7 @@ import java.util.Arrays;
import java.util.List;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.event.external.exception.ExternalEventConfigurationNotFoundException;
+import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventSourceService;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -50,11 +51,14 @@ public class ExternalEventConfigurationValidationServiceTest {
@Mock
private TenantDetailsService tenantDetailsService;
+ @Mock
+ private ExternalEventSourceService externalEventSourceService;
+
private ExternalEventConfigurationValidationService underTest;
@BeforeEach
public void setUp() {
- underTest = new ExternalEventConfigurationValidationService(tenantDetailsService, jdbcTemplateFactory);
+ underTest = new ExternalEventConfigurationValidationService(tenantDetailsService, jdbcTemplateFactory, externalEventSourceService);
}
@Test
@@ -98,7 +102,8 @@ public class ExternalEventConfigurationValidationServiceTest {
when(tenantDetailsService.findAllTenants()).thenReturn(tenants);
when(jdbcTemplateFactory.create(any())).thenReturn(jdbcTemplate);
when(jdbcTemplate.queryForList(anyString(), eq(String.class))).thenReturn(configurations);
-
+ List<String> sourcePackage = Arrays.asList("org.apache.fineract.infrastructure.event.business.domain");
+ when(externalEventSourceService.getSourcePackages()).thenReturn(sourcePackage);
// when
underTest.afterPropertiesSet();
@@ -117,7 +122,8 @@ public class ExternalEventConfigurationValidationServiceTest {
when(tenantDetailsService.findAllTenants()).thenReturn(tenants);
when(jdbcTemplateFactory.create(any())).thenReturn(jdbcTemplate);
when(jdbcTemplate.queryForList(anyString(), eq(String.class))).thenReturn(new ArrayList<>());
-
+ List<String> sourcePackage = Arrays.asList("org.apache.fineract.infrastructure.event.business.domain");
+ when(externalEventSourceService.getSourcePackages()).thenReturn(sourcePackage);
// when
ExternalEventConfigurationNotFoundException exceptionThrown = assertThrows(ExternalEventConfigurationNotFoundException.class,
() -> underTest.afterPropertiesSet());
@@ -171,7 +177,8 @@ public class ExternalEventConfigurationValidationServiceTest {
when(tenantDetailsService.findAllTenants()).thenReturn(tenants);
when(jdbcTemplateFactory.create(any())).thenReturn(jdbcTemplate);
when(jdbcTemplate.queryForList(anyString(), eq(String.class))).thenReturn(configurationWithMissingCentersCreateBusinessEvent);
-
+ List<String> sourcePackage = Arrays.asList("org.apache.fineract.infrastructure.event.business.domain");
+ when(externalEventSourceService.getSourcePackages()).thenReturn(sourcePackage);
// when
ExternalEventConfigurationNotFoundException exceptionThrown = assertThrows(ExternalEventConfigurationNotFoundException.class,
() -> underTest.afterPropertiesSet());