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/custom/acme/event/externalevent/src/main/resources/db/custom-changelog/0001_acme_external_event_configuration.xml b/custom/acme/event/externalevent/src/main/resources/db/custom-changelog/0001_acme_external_event_configuration.xml new file mode 100644 index 000000000..05a143eb7 --- /dev/null +++ b/custom/acme/event/externalevent/src/main/resources/db/custom-changelog/0001_acme_external_event_configuration.xml @@ -0,0 +1,31 @@ + + + + + + + + + + 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 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 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 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 getAllEventClasses() { - try (ScanResult scanResult = new ClassGraph().enableAllInfo().acceptPackages(EXTERNAL_EVENT_CLASSES_BASE_PACKAGE).scan()) { + List 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 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 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 providers; + + public List 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 sourcePackages; + + public SimpleExternalEventSourceProvider(Collection sourcePackages) { + this.sourcePackages = Set.copyOf(sourcePackages); + } + + @Override + public Set 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 @@ - + 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 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 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 sourcePackage = Arrays.asList("org.apache.fineract.infrastructure.event.business.domain"); + when(externalEventSourceService.getSourcePackages()).thenReturn(sourcePackage); // when ExternalEventConfigurationNotFoundException exceptionThrown = assertThrows(ExternalEventConfigurationNotFoundException.class, () -> underTest.afterPropertiesSet());