FINERACT-1724: Further upgrades

This commit is contained in:
Arnold Galovics
2023-06-06 11:45:08 +02:00
committed by Arnold Gálovics
parent bc4b707646
commit abb5d4abb5
14 changed files with 154 additions and 40 deletions
+1
View File
@@ -28,6 +28,7 @@ dependencies {
implementation( implementation(
'org.springframework.boot:spring-boot-starter-web', 'org.springframework.boot:spring-boot-starter-web',
'org.springframework.boot:spring-boot-starter-security', 'org.springframework.boot:spring-boot-starter-security',
'org.springframework.boot:spring-boot-starter-validation',
'jakarta.ws.rs:jakarta.ws.rs-api', 'jakarta.ws.rs:jakarta.ws.rs-api',
'org.glassfish.jersey.media:jersey-media-multipart', 'org.glassfish.jersey.media:jersey-media-multipart',
+4 -4
View File
@@ -155,10 +155,10 @@ dependencies {
driver 'mysql:mysql-connector-java:8.0.32' driver 'mysql:mysql-connector-java:8.0.32'
} }
//URLClassLoader loader = GroovyObject.class.classLoader URLClassLoader loader = GroovyObject.class.classLoader
//configurations.driver.each {File file -> configurations.driver.each {File file ->
// loader.addURL(file.toURL()) loader.addURL(file.toURL())
//} }
task createDB { task createDB {
description= "Creates the MariaDB Database. Needs database name to be passed (like: -PdbName=someDBname)" description= "Creates the MariaDB Database. Needs database name to be passed (like: -PdbName=someDBname)"
@@ -37,6 +37,7 @@ import org.springframework.batch.core.annotation.OnSkipInProcess;
import org.springframework.batch.core.annotation.OnSkipInRead; import org.springframework.batch.core.annotation.OnSkipInRead;
import org.springframework.batch.core.annotation.OnSkipInWrite; import org.springframework.batch.core.annotation.OnSkipInWrite;
import org.springframework.batch.core.annotation.OnWriteError; import org.springframework.batch.core.annotation.OnWriteError;
import org.springframework.batch.item.Chunk;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
@@ -79,25 +80,25 @@ public abstract class AbstractLoanItemListener {
} }
@OnWriteError @OnWriteError
public void onWriteError(Exception e, @NotNull List<? extends Loan> items) { public void onWriteError(Exception e, @NotNull Chunk<? extends Loan> items) {
List<Long> loanIds = items.stream().map(AbstractPersistableCustom::getId).toList(); List<Long> loanIds = items.getItems().stream().map(AbstractPersistableCustom::getId).toList();
log.warn("Error was triggered during writing of Loans (ids={}) due to: {}", loanIds, ThrowableSerialization.serialize(e)); log.warn("Error was triggered during writing of Loans (ids={}) due to: {}", loanIds, ThrowableSerialization.serialize(e));
updateAccountLockWithError(loanIds, "Loan (id: %d) writing is failed", e); updateAccountLockWithError(loanIds, "Loan (id: %d) writing is failed", e);
} }
@OnSkipInRead @OnSkipInRead
public void onSkipInRead(@NotNull Exception e) { public void onSkipInRead(@NotNull Throwable e) {
log.warn("Skipping was triggered during read!"); log.warn("Skipping was triggered during read!");
} }
@OnSkipInProcess @OnSkipInProcess
public void onSkipInProcess(@NotNull Loan item, @NotNull Exception e) { public void onSkipInProcess(@NotNull Loan item, @NotNull Throwable e) {
log.warn("Skipping was triggered during processing of Loan (id={})", item.getId()); log.warn("Skipping was triggered during processing of Loan (id={})", item.getId());
} }
@OnSkipInWrite @OnSkipInWrite
public void onSkipInWrite(@NotNull Loan item, @NotNull Exception e) { public void onSkipInWrite(@NotNull Loan item, @NotNull Throwable e) {
log.warn("Skipping was triggered during writing of Loan (id={})", item.getId()); log.warn("Skipping was triggered during writing of Loan (id={})", item.getId());
} }
@@ -22,14 +22,13 @@ import org.apache.fineract.infrastructure.cache.service.RuntimeDelegatingCacheMa
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer; import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@Configuration @Configuration
@EnableCaching @EnableCaching
public class PlatformCacheConfiguration extends CachingConfigurerSupport implements CachingConfigurer { public class PlatformCacheConfiguration implements CachingConfigurer {
@Autowired @Autowired
private RuntimeDelegatingCacheManager delegatingCacheManager; private RuntimeDelegatingCacheManager delegatingCacheManager;
@@ -38,7 +38,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
@@ -57,7 +57,7 @@ import org.springframework.security.web.context.SecurityContextHolderFilter;
@Configuration @Configuration
@ConditionalOnProperty("fineract.security.oauth.enabled") @ConditionalOnProperty("fineract.security.oauth.enabled")
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableMethodSecurity
public class OAuth2SecurityConfig { public class OAuth2SecurityConfig {
@Autowired @Autowired
@@ -76,9 +76,8 @@ public class OAuth2SecurityConfig {
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
http // http //
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
.securityMatcher("/api/**").authorizeHttpRequests((auth) -> { .securityMatcher("/api/**").authorizeHttpRequests((auth) -> {
auth auth
.requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() // .requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() //
@@ -90,7 +89,14 @@ public class OAuth2SecurityConfig {
.requestMatchers(HttpMethod.POST, "/api/*/twofactor/validate").fullyAuthenticated() // .requestMatchers(HttpMethod.POST, "/api/*/twofactor/validate").fullyAuthenticated() //
.requestMatchers("/api/*/twofactor").fullyAuthenticated() // .requestMatchers("/api/*/twofactor").fullyAuthenticated() //
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); // .requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); //
}) // });
return http.build();
}
@Bean
public SecurityFilterChain FilterChain(HttpSecurity http) throws Exception {
http //
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
.exceptionHandling((ehc) -> ehc.authenticationEntryPoint(new OAuth2ExceptionEntryPoint())) .exceptionHandling((ehc) -> ehc.authenticationEntryPoint(new OAuth2ExceptionEntryPoint()))
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(authenticationConverter())) .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(authenticationConverter()))
.authenticationEntryPoint(new OAuth2ExceptionEntryPoint())) // .authenticationEntryPoint(new OAuth2ExceptionEntryPoint())) //
@@ -40,7 +40,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.factory.PasswordEncoderFactories;
@@ -53,7 +53,7 @@ import org.springframework.security.web.context.SecurityContextHolderFilter;
@Configuration @Configuration
@ConditionalOnProperty("fineract.security.basicauth.enabled") @ConditionalOnProperty("fineract.security.basicauth.enabled")
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableMethodSecurity
public class SecurityConfig { public class SecurityConfig {
@Autowired @Autowired
@@ -78,9 +78,8 @@ public class SecurityConfig {
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
http // http //
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
.securityMatcher("/api/**").authorizeHttpRequests((auth) -> { .securityMatcher("/api/**").authorizeHttpRequests((auth) -> {
auth auth
.requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() // .requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() //
@@ -94,13 +93,20 @@ public class SecurityConfig {
.requestMatchers("/api/*/twofactor").fullyAuthenticated() // .requestMatchers("/api/*/twofactor").fullyAuthenticated() //
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"))); // .requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"))); //
}) // }) //
.httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint())) // .httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint())); //
return http.build();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http //
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
.sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // .sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
.addFilterAfter(fineractInstanceModeApiFilter, SecurityContextHolderFilter.class) // .addFilterAfter(fineractInstanceModeApiFilter, SecurityContextHolderFilter.class) //
.addFilterAfter(tenantAwareBasicAuthenticationFilter(), FineractInstanceModeApiFilter.class) // .addFilterAfter(tenantAwareBasicAuthenticationFilter(), FineractInstanceModeApiFilter.class) //
.addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class) // .addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class) //
.addFilterAfter(loanCOBApiFilter, InsecureTwoFactorAuthenticationFilter.class) .addFilterAfter(loanCOBApiFilter, InsecureTwoFactorAuthenticationFilter.class) //
.addFilterBefore(idempotencyStoreFilter, ExceptionTranslationFilter.class); .addFilterBefore(idempotencyStoreFilter, ExceptionTranslationFilter.class); //
if (serverProperties.getSsl().isEnabled()) { if (serverProperties.getSsl().isEnabled()) {
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure()); http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
@@ -20,8 +20,8 @@ package org.apache.fineract.infrastructure.core.diagnostics.performance.sampling
import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toMap;
import java.time.Duration;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.diagnostics.performance.sampling.core.SamplingConfiguration; import org.apache.fineract.infrastructure.core.diagnostics.performance.sampling.core.SamplingConfiguration;
@@ -54,8 +54,9 @@ public class SamplingScheduler implements InitializingBean {
log.warn("Reset period for sampling cannot be smaller than 10 seconds, setting back the minimum 10"); log.warn("Reset period for sampling cannot be smaller than 10 seconds, setting back the minimum 10");
resetPeriodInSec = 10; resetPeriodInSec = 10;
} }
PeriodicTrigger trigger = new PeriodicTrigger(resetPeriodInSec, TimeUnit.SECONDS); Duration resetPeriodInSecDuration = Duration.ofSeconds(resetPeriodInSec);
trigger.setInitialDelay(resetPeriodInSec); PeriodicTrigger trigger = new PeriodicTrigger(resetPeriodInSecDuration);
trigger.setInitialDelay(resetPeriodInSecDuration);
taskScheduler.schedule(this::printAndResetPeriodically, trigger); taskScheduler.schedule(this::printAndResetPeriodically, trigger);
} }
@@ -36,7 +36,7 @@ import org.springframework.stereotype.Service;
* The {@link RoutingDataSourceService} is responsible for returning the appropriate {@link DataSource} for the tenant * The {@link RoutingDataSourceService} is responsible for returning the appropriate {@link DataSource} for the tenant
* of this request. * of this request.
*/ */
@Service(value = "routingDataSource") @Service(value = "dataSource")
@Primary @Primary
public class RoutingDataSource extends AbstractDataSource { public class RoutingDataSource extends AbstractDataSource {
@@ -25,8 +25,11 @@ import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourc
import org.springframework.batch.core.configuration.JobRegistry; import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher; import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher;
import org.springframework.batch.core.repository.JobRepository; 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.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
@@ -34,7 +37,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
@Configuration @Configuration(proxyBeanMethods = false)
@EnableBatchProcessing @EnableBatchProcessing
public class ScheduledJobRunnerConfig { public class ScheduledJobRunnerConfig {
@@ -49,19 +52,31 @@ public class ScheduledJobRunnerConfig {
} }
@Bean @Bean
public JobRepositoryFactoryBean jobRepositoryFactoryBean(RoutingDataSource routingDataSource, public Jackson2ExecutionContextStringSerializer executionContextSerializer() {
PlatformTransactionManager transactionManager) throws Exception { return new Jackson2ExecutionContextStringSerializer();
}
@Bean
public JobRepository jobRepository(RoutingDataSource routingDataSource,
PlatformTransactionManager transactionManager) throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(routingDataSource); factory.setDataSource(routingDataSource);
factory.setTransactionManager(transactionManager); factory.setTransactionManager(transactionManager);
factory.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED"); factory.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED");
factory.setSerializer(executionContextSerializer());
factory.afterPropertiesSet(); factory.afterPropertiesSet();
return factory; return factory.getObject();
} }
@Bean @Bean
public JobRepository jobRepository(JobRepositoryFactoryBean factory) throws Exception { public JobExplorer jobExplorer(RoutingDataSource routingDataSource,
return factory.getObject(); PlatformTransactionManager transactionManager) throws Exception {
JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
jobExplorerFactoryBean.setDataSource(routingDataSource);
jobExplorerFactoryBean.setTransactionManager(transactionManager);
jobExplorerFactoryBean.setSerializer(executionContextSerializer());
jobExplorerFactoryBean.afterPropertiesSet();
return jobExplorerFactoryBean.getObject();
} }
@Bean @Bean
@@ -0,0 +1,32 @@
/**
* 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();
}
}
@@ -60,7 +60,7 @@ public interface CalendarInstanceRepository extends JpaRepository<CalendarInstan
* EntityType = 3 is for loan * EntityType = 3 is for loan
*/ */
@Query("SELECT COUNT(ci.id) FROM CalendarInstance ci, Loan ln WHERE ln.id = ci.entityId AND ci.entityTypeId = 3 AND ci.calendar.id = :calendarId AND ln.loanStatus IN :loanStatuses ") @Query("SELECT COUNT(ci.id) FROM CalendarInstance ci, Loan loan WHERE loan.id = ci.entityId AND ci.entityTypeId = 3 AND ci.calendar.id = :calendarId AND loan.loanStatus IN :loanStatuses ")
Integer countOfLoansSyncedWithCalendar(@Param("calendarId") Long calendarId, @Param("loanStatuses") Collection<Integer> loanStatuses); Integer countOfLoansSyncedWithCalendar(@Param("calendarId") Long calendarId, @Param("loanStatuses") Collection<Integer> loanStatuses);
} }
@@ -29,10 +29,10 @@
<persistence-unit-metadata> <persistence-unit-metadata>
<persistence-unit-defaults> <persistence-unit-defaults>
<delimited-identifiers/> <delimited-identifiers/>
<entity-listeners> <!-- <entity-listeners>-->
<entity-listener <!-- <entity-listener-->
class="org.springframework.data.jpa.domain.support.AuditingEntityListener" /> <!-- class="org.springframework.data.jpa.domain.support.AuditingEntityListener" />-->
</entity-listeners> <!-- </entity-listeners>-->
</persistence-unit-defaults> </persistence-unit-defaults>
</persistence-unit-metadata> </persistence-unit-metadata>
@@ -30,6 +30,40 @@
<dropColumn tableName="BATCH_JOB_EXECUTION" columnName="JOB_CONFIGURATION_LOCATION"/> <dropColumn tableName="BATCH_JOB_EXECUTION" columnName="JOB_CONFIGURATION_LOCATION"/>
</changeSet> </changeSet>
<changeSet author="fineract" id="2" context="postgresql"> <changeSet author="fineract" id="2" context="postgresql">
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = TO_CHAR(DATE_VAL, 'YYYY-MM-DDTHH:MM:SSZ')
WHERE TYPE_CD = 'DATE'
</sql>
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = CAST(LONG_VAL AS CHAR)
WHERE TYPE_CD = 'LONG'
</sql>
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = CAST(DOUBLE_VAL AS CHAR)
WHERE TYPE_CD = 'DOUBLE'
</sql>
</changeSet>
<changeSet author="fineract" id="2" context="mysql">
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = DATE_FORMAT(DATE_VAL, 'YYYY-MM-DDTHH:MM:SSZ')
WHERE TYPE_CD = 'DATE'
</sql>
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = LONG_VAL::text
WHERE TYPE_CD = 'LONG'
</sql>
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = DOUBLE_VAL::text
WHERE TYPE_CD = 'DOUBLE'
</sql>
</changeSet>
<changeSet author="fineract" id="4" context="postgresql">
<!-- <!--
org/springframework/batch/core/migration/5.0/migration-postgresql.sql org/springframework/batch/core/migration/5.0/migration-postgresql.sql
--> -->
@@ -58,7 +92,7 @@
</sql> </sql>
</changeSet> </changeSet>
<changeSet author="fineract" id="3" context="mysql"> <changeSet author="fineract" id="4" context="mysql">
<!-- <!--
org/springframework/batch/core/migration/5.0/migration-mysql.sql org/springframework/batch/core/migration/5.0/migration-mysql.sql
--> -->
@@ -75,4 +109,22 @@
ALTER TABLE BATCH_JOB_EXECUTION_PARAMS CHANGE COLUMN STRING_VAL PARAMETER_VALUE VARCHAR(2500); ALTER TABLE BATCH_JOB_EXECUTION_PARAMS CHANGE COLUMN STRING_VAL PARAMETER_VALUE VARCHAR(2500);
</sql> </sql>
</changeSet> </changeSet>
<changeSet author="fineract" id="5">
<update tableName="BATCH_JOB_EXECUTION_PARAMS">
<column name="PARAMETER_TYPE" value="java.lang.Long"/>
<where>PARAMETER_TYPE='LONG'</where>
</update>
<update tableName="BATCH_JOB_EXECUTION_PARAMS">
<column name="PARAMETER_TYPE" value="java.lang.String"/>
<where>PARAMETER_TYPE='STRING'</where>
</update>
<update tableName="BATCH_JOB_EXECUTION_PARAMS">
<column name="PARAMETER_TYPE" value="java.lang.Double"/>
<where>PARAMETER_TYPE='DOUBLE'</where>
</update>
<update tableName="BATCH_JOB_EXECUTION_PARAMS">
<column name="PARAMETER_TYPE" value="java.util.Date"/>
<where>PARAMETER_TYPE='DATE'</where>
</update>
</changeSet>
</databaseChangeLog> </databaseChangeLog>
@@ -38,6 +38,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.batch.item.Chunk;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
@@ -107,7 +108,7 @@ public class LoanItemListenerStepDefinitions implements En {
}); });
When("LoanItemListener.onWriteError method executed", () -> { When("LoanItemListener.onWriteError method executed", () -> {
loanItemListener.onWriteError(exception, List.of(loan)); loanItemListener.onWriteError(exception, new Chunk<>(List.of(loan)));
}); });
Then("LoanItemListener.onWriteError result should match", () -> { Then("LoanItemListener.onWriteError result should match", () -> {