FINERACT-1724: Further upgrades
This commit is contained in:
committed by
Arnold Gálovics
parent
bc4b707646
commit
abb5d4abb5
@@ -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',
|
||||||
|
|
||||||
|
|||||||
@@ -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)"
|
||||||
|
|||||||
+6
-5
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -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;
|
||||||
|
|||||||
+11
-5
@@ -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())) //
|
||||||
|
|||||||
+13
-7
@@ -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());
|
||||||
|
|||||||
+4
-3
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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 {
|
||||||
|
|
||||||
|
|||||||
+21
-6
@@ -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
|
||||||
|
|||||||
+32
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -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>
|
||||||
|
|
||||||
|
|||||||
+53
-1
@@ -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>
|
||||||
|
|||||||
+2
-1
@@ -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", () -> {
|
||||||
|
|||||||
Reference in New Issue
Block a user