diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/jpa/EntityManagerFactoryCustomizer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/jpa/EntityManagerFactoryCustomizer.java new file mode 100644 index 000000000..e2a77c959 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/jpa/EntityManagerFactoryCustomizer.java @@ -0,0 +1,64 @@ +/** + * 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.core.config.jpa; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor; + +/** + * A customizer interface for the EntityManager factories. Register an implementation of this interface as a Spring + * bean, and it'll be picked up automatically.
+ *
+ * Multiple customizers could be registered and all of them will be picked up by the application.
+ *
+ * The order in which the customizations are applied is not guaranteed. + * + * @see JPAConfig + */ +public interface EntityManagerFactoryCustomizer { + + /** + * Additional packages to scan, for example in case of custom modules. + * + * @return a Set of package names, not null + */ + default Set additionalPackagesToScan() { + return Collections.emptySet(); + } + + /** + * Additional vendor properties to be passed to EclipseLink; useful in case of fine-tuning. + * + * @return a Set of vendor properties, not null + */ + default Map additionalVendorProperties() { + return Collections.emptyMap(); + } + + /** + * Additional {@link PersistenceUnitPostProcessor} configuration in case customizations are required. + * + * @return Set of PersistenceUnitPostProcessors, not null + */ + default Set additionalPersistenceUnitPostProcessors() { + return Collections.emptySet(); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/jpa/JPAConfig.java similarity index 70% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/jpa/JPAConfig.java index 2061fdb6e..77c1f7866 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/jpa/JPAConfig.java @@ -17,9 +17,13 @@ * under the License. */ -package org.apache.fineract.infrastructure.core.config; +package org.apache.fineract.infrastructure.core.config.jpa; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.apache.fineract.infrastructure.core.auditing.JpaAuditingHandlerRegistrar; import org.apache.fineract.infrastructure.core.domain.AuditorAwareImpl; import org.apache.fineract.infrastructure.core.persistence.DatabaseSelectingPersistenceUnitPostProcessor; @@ -43,6 +47,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager; +import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor; import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; @@ -57,11 +62,13 @@ import org.springframework.transaction.support.TransactionTemplate; public class JPAConfig extends JpaBaseConfiguration { private final DatabaseTypeResolver databaseTypeResolver; + private final Collection emFactoryCustomizers; public JPAConfig(RoutingDataSource dataSource, JpaProperties properties, ObjectProvider jtaTransactionManager, - DatabaseTypeResolver databaseTypeResolver) { + DatabaseTypeResolver databaseTypeResolver, Collection customizers) { super(dataSource, properties, jtaTransactionManager); this.databaseTypeResolver = databaseTypeResolver; + this.emFactoryCustomizers = customizers; } @Override @@ -70,9 +77,27 @@ public class JPAConfig extends JpaBaseConfiguration { @DependsOn("tenantDatabaseUpgradeService") public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder) { Map vendorProperties = getVendorProperties(); - customizeVendorProperties(vendorProperties); - return factoryBuilder.dataSource(getDataSource()).properties(vendorProperties).persistenceUnit("jpa-pu") - .packages("org.apache.fineract").jta(false).build(); + String[] packagesToScan = getPackagesToScan(); + return factoryBuilder.dataSource(getDataSource()).properties(vendorProperties).persistenceUnit("jpa-pu").packages(packagesToScan) + .jta(false).build(); + } + + @Override + protected Map getVendorProperties() { + Map vendorProperties = new HashMap<>(); + vendorProperties.put(PersistenceUnitProperties.WEAVING, "static"); + vendorProperties.put(PersistenceUnitProperties.PERSISTENCE_CONTEXT_CLOSE_ON_COMMIT, "true"); + vendorProperties.put(PersistenceUnitProperties.CACHE_SHARED_DEFAULT, "false"); + emFactoryCustomizers.forEach(c -> vendorProperties.putAll(c.additionalVendorProperties())); + return vendorProperties; + } + + @Override + protected String[] getPackagesToScan() { + Set packagesToScan = new HashSet<>(); + packagesToScan.add("org.apache.fineract"); + emFactoryCustomizers.forEach(c -> packagesToScan.addAll(c.additionalPackagesToScan())); + return packagesToScan.toArray(String[]::new); } @Override @@ -80,21 +105,22 @@ public class JPAConfig extends JpaBaseConfiguration { ObjectProvider persistenceUnitManager, ObjectProvider customizers) { EntityManagerFactoryBuilder builder = super.entityManagerFactoryBuilder(jpaVendorAdapter, persistenceUnitManager, customizers); - builder.setPersistenceUnitPostProcessors(new DatabaseSelectingPersistenceUnitPostProcessor(databaseTypeResolver)); + builder.setPersistenceUnitPostProcessors(getPersistenceUnitPostProcessors()); return builder; } + private PersistenceUnitPostProcessor[] getPersistenceUnitPostProcessors() { + Set processors = new HashSet<>(); + processors.add(new DatabaseSelectingPersistenceUnitPostProcessor(databaseTypeResolver)); + emFactoryCustomizers.forEach(c -> processors.addAll(c.additionalPersistenceUnitPostProcessors())); + return processors.toArray(PersistenceUnitPostProcessor[]::new); + } + @Override protected AbstractJpaVendorAdapter createJpaVendorAdapter() { return new EclipseLinkJpaVendorAdapter(); } - @Override - protected Map getVendorProperties() { - return Map.of(PersistenceUnitProperties.WEAVING, "static", PersistenceUnitProperties.PERSISTENCE_CONTEXT_CLOSE_ON_COMMIT, "true", - PersistenceUnitProperties.CACHE_SHARED_DEFAULT, "false"); - } - @Bean public AuditorAware auditorAware() { return new AuditorAwareImpl();