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 2023/06/06 09:45:31 UTC
[fineract] 14/15: FINERACT-1724: Backward compatibility fix for MariaDB on sequence vs table incrementers + SQL grammar fix for Loan COB catchup
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 <ga...@gmail.com>
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(