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
commit c437c5a48b802ca8be956a42c304f633f461ce9d Author: Arnold Galovics <[email protected]> AuthorDate: Mon Jun 5 15:35:16 2023 +0200 FINERACT-1724: Backward compatibility fix for MariaDB on sequence vs table incrementers + SQL grammar fix for Loan COB catchup --- .../database/DatabaseSpecificSQLGenerator.java | 6 +- .../jobs/ScheduledJobRunnerConfig.java | 10 +++ .../jobs/config/FineractBatchConfiguration.java | 32 --------- ...ineractDataFieldMaxValueIncrementerFactory.java | 83 ++++++++++++++++++++++ .../jobs/domain/JobExecutionRepository.java | 2 +- 5 files changed, 97 insertions(+), 36 deletions(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java index 7e64b4794..fc9591992 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabaseSpecificSQLGenerator.java @@ -160,11 +160,11 @@ public class DatabaseSpecificSQLGenerator { } } - public String castBigInt(String sql) { + public String castInteger(String sql) { if (databaseTypeResolver.isMySQL()) { - return format("CAST(%s AS BIGINT)", sql); + return format("CAST(%s AS SIGNED INTEGER)", sql); } else if (databaseTypeResolver.isPostgreSQL()) { - return format("%s::BIGINT", sql); + return format("%s::INTEGER", sql); } else { throw new IllegalStateException("Database type is not supported for casting to bigint " + databaseTypeResolver.databaseType()); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/ScheduledJobRunnerConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/ScheduledJobRunnerConfig.java index a9b69684d..ca7a0b552 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/ScheduledJobRunnerConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/ScheduledJobRunnerConfig.java @@ -22,6 +22,7 @@ import java.util.List; import org.apache.fineract.infrastructure.core.persistence.ExtendedJpaTransactionManager; import org.apache.fineract.infrastructure.core.persistence.TransactionLifecycleCallback; import org.apache.fineract.infrastructure.core.service.database.RoutingDataSource; +import org.apache.fineract.infrastructure.jobs.config.FineractDataFieldMaxValueIncrementerFactory; import org.springframework.batch.core.configuration.JobRegistry; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; @@ -31,6 +32,7 @@ import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer; import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean; +import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; import org.springframework.context.annotation.Bean; @@ -56,6 +58,13 @@ public class ScheduledJobRunnerConfig { return new Jackson2ExecutionContextStringSerializer(); } + @Bean + public DataFieldMaxValueIncrementerFactory incrementerFactory(RoutingDataSource routingDataSource) { + // The DefaultDataFieldMaxValueIncrementerFactory has to be overridden because Spring 6 introduced + // a new MariaDB incrementer that's incompatible with Spring Batch 4.x + return new FineractDataFieldMaxValueIncrementerFactory(routingDataSource); + } + @Bean public JobRepository jobRepository(RoutingDataSource routingDataSource, PlatformTransactionManager transactionManager) throws Exception { @@ -64,6 +73,7 @@ public class ScheduledJobRunnerConfig { factory.setTransactionManager(transactionManager); factory.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED"); factory.setSerializer(executionContextSerializer()); + factory.setIncrementerFactory(incrementerFactory(routingDataSource)); factory.afterPropertiesSet(); return factory.getObject(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/config/FineractBatchConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/config/FineractBatchConfiguration.java deleted file mode 100644 index ed8ca3ae3..000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/config/FineractBatchConfiguration.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * 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.jobs.config; - -import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration; -import org.springframework.batch.core.repository.ExecutionContextSerializer; -import org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer; - -//@Configuration(proxyBeanMethods = false) -public class FineractBatchConfiguration extends DefaultBatchConfiguration { - - @Override - protected ExecutionContextSerializer getExecutionContextSerializer() { - return new Jackson2ExecutionContextStringSerializer(); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/config/FineractDataFieldMaxValueIncrementerFactory.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/config/FineractDataFieldMaxValueIncrementerFactory.java new file mode 100644 index 000000000..8efe5476a --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/config/FineractDataFieldMaxValueIncrementerFactory.java @@ -0,0 +1,83 @@ +/** + * 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.jobs.config; + +import static org.springframework.batch.support.DatabaseType.MARIADB; +import static org.springframework.batch.support.DatabaseType.MYSQL; +import static org.springframework.batch.support.DatabaseType.POSTGRES; + +import java.util.List; +import javax.sql.DataSource; +import lombok.RequiredArgsConstructor; +import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory; +import org.springframework.batch.support.DatabaseType; +import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer; +import org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer; +import org.springframework.jdbc.support.incrementer.PostgresSequenceMaxValueIncrementer; + +@RequiredArgsConstructor +public class FineractDataFieldMaxValueIncrementerFactory implements DataFieldMaxValueIncrementerFactory { + + private static final List<DatabaseType> SUPPORTED_DATABASE_TYPES = List.of(MARIADB, MYSQL, POSTGRES); + + private final DataSource dataSource; + + private String incrementerColumnName = "ID"; + + /** + * Public setter for the column name (defaults to "ID") in the incrementer. Only used by some platforms (Derby, + * HSQL, MySQL, SQL Server and Sybase), and should be fine for use with Spring Batch meta data as long as the + * default batch schema hasn't been changed. + * + * @param incrementerColumnName + * the primary key column name to set + */ + public void setIncrementerColumnName(String incrementerColumnName) { + this.incrementerColumnName = incrementerColumnName; + } + + @Override + public DataFieldMaxValueIncrementer getIncrementer(String incrementerType, String incrementerName) { + DatabaseType databaseType = getDatabaseType(incrementerType); + if (databaseType == MYSQL || databaseType == MARIADB) { + MySQLMaxValueIncrementer mySQLMaxValueIncrementer = new MySQLMaxValueIncrementer(dataSource, incrementerName, + incrementerColumnName); + mySQLMaxValueIncrementer.setUseNewConnection(true); + return mySQLMaxValueIncrementer; + } else if (databaseType == POSTGRES) { + return new PostgresSequenceMaxValueIncrementer(dataSource, incrementerName); + } + throw new IllegalArgumentException("databaseType argument was not on the approved list"); + } + + @Override + public boolean isSupportedIncrementerType(String incrementerType) { + DatabaseType databaseType = getDatabaseType(incrementerType); + return SUPPORTED_DATABASE_TYPES.contains(databaseType); + } + + @Override + public String[] getSupportedIncrementerTypes() { + return SUPPORTED_DATABASE_TYPES.stream().map(DatabaseType::name).toArray(String[]::new); + } + + private DatabaseType getDatabaseType(String incrementerType) { + return DatabaseType.valueOf(incrementerType.toUpperCase()); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/domain/JobExecutionRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/domain/JobExecutionRepository.java index 3b2ee3dd4..0db04e4ac 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/domain/JobExecutionRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/domain/JobExecutionRepository.java @@ -172,7 +172,7 @@ public class JobExecutionRepository implements InitializingBean { sqlStatementBuilder.append( "SELECT bje.JOB_EXECUTION_ID FROM BATCH_JOB_INSTANCE bji INNER JOIN BATCH_JOB_EXECUTION bje ON bji.JOB_INSTANCE_ID = bje.JOB_INSTANCE_ID INNER JOIN BATCH_JOB_EXECUTION_PARAMS bjep ON bje.JOB_EXECUTION_ID = bjep.JOB_EXECUTION_ID" + " WHERE bje.STATUS IN (:statuses) AND bji.JOB_NAME = :jobName AND bjep.PARAMETER_NAME = :jobCustomParamKeyName AND " - + sqlGenerator.castBigInt("bjep.PARAMETER_VALUE") + " IN (" + getSubQueryForCustomJobParameters() + + sqlGenerator.castInteger("bjep.PARAMETER_VALUE") + " IN (" + getSubQueryForCustomJobParameters() + ") AND bje.JOB_INSTANCE_ID NOT IN (SELECT bje.JOB_INSTANCE_ID FROM BATCH_JOB_INSTANCE bji INNER JOIN BATCH_JOB_EXECUTION bje ON bji.JOB_INSTANCE_ID = bje.JOB_INSTANCE_ID" + " WHERE bje.STATUS = :completedStatus AND bji.JOB_NAME = :jobName)"); return namedParameterJdbcTemplate.queryForList(
