initial commit

This commit is contained in:
Ivan Nikolaev-Axenov 2026-05-14 15:27:41 +03:00
parent eeede7b6e9
commit 32c4836c7c
44 changed files with 4252 additions and 0 deletions

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
/mvnw text eol=lf
*.cmd text eol=crlf

35
.gitignore vendored Normal file
View file

@ -0,0 +1,35 @@
HELP.md
target/
.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
logs/

12
.mvn/local-settings.xml Normal file
View file

@ -0,0 +1,12 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 http://maven.apache.org/xsd/settings-1.2.0.xsd">
<mirrors>
<mirror>
<id>mfd-unblocker</id>
<name>mfd-unblocker</name>
<mirrorOf>mfd</mirrorOf>
<url>http://10.200.200.131:8888/repository/internal/</url>
</mirror>
</mirrors>
</settings>

1
.mvn/maven.config Normal file
View file

@ -0,0 +1 @@
--settings=./.mvn/local-settings.xml

3
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View file

@ -0,0 +1,3 @@
wrapperVersion=3.3.4
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.15/apache-maven-3.9.15-bin.zip

Binary file not shown.

295
mvnw vendored Normal file
View file

@ -0,0 +1,295 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# 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.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.3.4
#
# Optional ENV vars
# -----------------
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
# MVNW_REPOURL - repo url base for downloading maven distribution
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
# ----------------------------------------------------------------------------
set -euf
[ "${MVNW_VERBOSE-}" != debug ] || set -x
# OS specific support.
native_path() { printf %s\\n "$1"; }
case "$(uname)" in
CYGWIN* | MINGW*)
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
native_path() { cygpath --path --windows "$1"; }
;;
esac
# set JAVACMD and JAVACCMD
set_java_home() {
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
if [ -n "${JAVA_HOME-}" ]; then
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACCMD="$JAVA_HOME/jre/sh/javac"
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACCMD="$JAVA_HOME/bin/javac"
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
return 1
fi
fi
else
JAVACMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v java
)" || :
JAVACCMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v javac
)" || :
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
return 1
fi
fi
}
# hash string like Java String::hashCode
hash_string() {
str="${1:-}" h=0
while [ -n "$str" ]; do
char="${str%"${str#?}"}"
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
str="${str#?}"
done
printf %x\\n $h
}
verbose() { :; }
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
die() {
printf %s\\n "$1" >&2
exit 1
}
trim() {
# MWRAPPER-139:
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
# Needed for removing poorly interpreted newline sequences when running in more
# exotic environments such as mingw bash on Windows.
printf "%s" "${1}" | tr -d '[:space:]'
}
scriptDir="$(dirname "$0")"
scriptName="$(basename "$0")"
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
while IFS="=" read -r key value; do
case "${key-}" in
distributionUrl) distributionUrl=$(trim "${value-}") ;;
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
esac
done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties"
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
case "${distributionUrl##*/}" in
maven-mvnd-*bin.*)
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
*)
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
distributionPlatform=linux-amd64
;;
esac
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
;;
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
esac
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
distributionUrlName="${distributionUrl##*/}"
distributionUrlNameMain="${distributionUrlName%.*}"
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
exec_maven() {
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
}
if [ -d "$MAVEN_HOME" ]; then
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
exec_maven "$@"
fi
case "${distributionUrl-}" in
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
esac
# prepare tmp dir
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
trap clean HUP INT TERM EXIT
else
die "cannot create temp dir"
fi
mkdir -p -- "${MAVEN_HOME%/*}"
# Download and Install Apache Maven
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
verbose "Downloading from: $distributionUrl"
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
# select .zip or .tar.gz
if ! command -v unzip >/dev/null; then
distributionUrl="${distributionUrl%.zip}.tar.gz"
distributionUrlName="${distributionUrl##*/}"
fi
# verbose opt
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
# normalize http auth
case "${MVNW_PASSWORD:+has-password}" in
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
esac
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
verbose "Found wget ... using wget"
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
verbose "Found curl ... using curl"
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
elif set_java_home; then
verbose "Falling back to use Java to download"
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
cat >"$javaSource" <<-END
public class Downloader extends java.net.Authenticator
{
protected java.net.PasswordAuthentication getPasswordAuthentication()
{
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
}
public static void main( String[] args ) throws Exception
{
setDefault( new Downloader() );
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
}
}
END
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
verbose " - Compiling Downloader.java ..."
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
verbose " - Running Downloader.java ..."
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
fi
# If specified, validate the SHA-256 sum of the Maven distribution zip file
if [ -n "${distributionSha256Sum-}" ]; then
distributionSha256Result=false
if [ "$MVN_CMD" = mvnd.sh ]; then
echo "Checksum validation is not supported for maven-mvnd." >&2
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
elif command -v sha256sum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then
distributionSha256Result=true
fi
elif command -v shasum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
distributionSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
fi
if [ $distributionSha256Result = false ]; then
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
exit 1
fi
fi
# unzip and move
if command -v unzip >/dev/null; then
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
else
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
fi
# Find the actual extracted directory name (handles snapshots where filename != directory name)
actualDistributionDir=""
# First try the expected directory name (for regular distributions)
if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then
if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then
actualDistributionDir="$distributionUrlNameMain"
fi
fi
# If not found, search for any directory with the Maven executable (for snapshots)
if [ -z "$actualDistributionDir" ]; then
# enable globbing to iterate over items
set +f
for dir in "$TMP_DOWNLOAD_DIR"/*; do
if [ -d "$dir" ]; then
if [ -f "$dir/bin/$MVN_CMD" ]; then
actualDistributionDir="$(basename "$dir")"
break
fi
fi
done
set -f
fi
if [ -z "$actualDistributionDir" ]; then
verbose "Contents of $TMP_DOWNLOAD_DIR:"
verbose "$(ls -la "$TMP_DOWNLOAD_DIR")"
die "Could not find Maven distribution directory in extracted archive"
fi
verbose "Found extracted Maven distribution directory: $actualDistributionDir"
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url"
mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
clean || :
exec_maven "$@"

189
mvnw.cmd vendored Normal file
View file

@ -0,0 +1,189 @@
<# : batch portion
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Apache Maven Wrapper startup batch script, version 3.3.4
@REM
@REM Optional ENV vars
@REM MVNW_REPOURL - repo url base for downloading maven distribution
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
@REM ----------------------------------------------------------------------------
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
@SET __MVNW_CMD__=
@SET __MVNW_ERROR__=
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
@SET PSModulePath=
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
)
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
@SET __MVNW_PSMODULEP_SAVE=
@SET __MVNW_ARG0_NAME__=
@SET MVNW_USERNAME=
@SET MVNW_PASSWORD=
@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*)
@echo Cannot start maven from wrapper >&2 && exit /b 1
@GOTO :EOF
: end batch / begin powershell #>
$ErrorActionPreference = "Stop"
if ($env:MVNW_VERBOSE -eq "true") {
$VerbosePreference = "Continue"
}
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
if (!$distributionUrl) {
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
}
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
"maven-mvnd-*" {
$USE_MVND = $true
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
$MVN_CMD = "mvnd.cmd"
break
}
default {
$USE_MVND = $false
$MVN_CMD = $script -replace '^mvnw','mvn'
break
}
}
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
if ($env:MVNW_REPOURL) {
$MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" }
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')"
}
$distributionUrlName = $distributionUrl -replace '^.*/',''
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
$MAVEN_M2_PATH = "$HOME/.m2"
if ($env:MAVEN_USER_HOME) {
$MAVEN_M2_PATH = "$env:MAVEN_USER_HOME"
}
if (-not (Test-Path -Path $MAVEN_M2_PATH)) {
New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null
}
$MAVEN_WRAPPER_DISTS = $null
if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {
$MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists"
} else {
$MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists"
}
$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain"
$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
exit $?
}
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
}
# prepare tmp dir
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
trap {
if ($TMP_DOWNLOAD_DIR.Exists) {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
}
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
# Download and Install Apache Maven
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
Write-Verbose "Downloading from: $distributionUrl"
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
$webclient = New-Object System.Net.WebClient
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
# If specified, validate the SHA-256 sum of the Maven distribution zip file
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
if ($distributionSha256Sum) {
if ($USE_MVND) {
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
}
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
}
}
# unzip and move
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
# Find the actual extracted directory name (handles snapshots where filename != directory name)
$actualDistributionDir = ""
# First try the expected directory name (for regular distributions)
$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain"
$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD"
if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {
$actualDistributionDir = $distributionUrlNameMain
}
# If not found, search for any directory with the Maven executable (for snapshots)
if (!$actualDistributionDir) {
Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object {
$testPath = Join-Path $_.FullName "bin/$MVN_CMD"
if (Test-Path -Path $testPath -PathType Leaf) {
$actualDistributionDir = $_.Name
}
}
}
if (!$actualDistributionDir) {
Write-Error "Could not find Maven distribution directory in extracted archive"
}
Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir"
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null
try {
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
} catch {
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
Write-Error "fail to move MAVEN_HOME"
}
} finally {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"

248
pom.xml Normal file
View file

@ -0,0 +1,248 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ru.nbch</groupId>
<artifactId>indic-search-service</artifactId>
<version>0.0.1</version>
<name>indic-search-service</name>
<description>indic-search-service</description>
<properties>
<java.version>21</java.version>
<registry.url>10.230.238.56:5000</registry.url>
<!-- <registry.url>nexus-dev.nbki.msk</registry.url>-->
<!-- <registry.url>rh8-vm3.nbki.msk:5000</registry.url>-->
<mybatis-spring.version>4.0.1</mybatis-spring.version>
<springdoc-openapi.version>3.0.3</springdoc-openapi.version>
<apm-agent-api.version>1.55.6</apm-agent-api.version>
<logstash-logback-encoder.version>9.0</logstash-logback-encoder.version>
<poi.version>5.5.1</poi.version>
<docker-maven-plugin.version>0.48.1</docker-maven-plugin.version>
</properties>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aspectj</artifactId>
</dependency>
<!-- Database -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.ibm.db2</groupId>
<artifactId>jcc</artifactId>
<scope>runtime</scope>
</dependency>
<!-- OpenAPI -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc-openapi.version}</version>
</dependency>
<!-- APM -->
<dependency>
<groupId>co.elastic.apm</groupId>
<artifactId>apm-agent-api</artifactId>
<version>${apm-agent-api.version}</version>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>${logstash-logback-encoder.version}</version>
</dependency>
<!-- XLSX documents -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>${mybatis-spring.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>application.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
@{argLine}
-javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar
-Xshare:off
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.14</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>with-docker-registry</id>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker-maven-plugin.version}</version>
<executions>
<execution>
<id>build</id>
<phase>install</phase>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- todo: For nexus, waiting for access -->
<!-- <authConfig>-->
<!-- &lt;!&ndash;suppress UnresolvedMavenProperty &ndash;&gt;-->
<!-- <username>${env.NEXUS_USERNAME}</username>-->
<!-- &lt;!&ndash;suppress UnresolvedMavenProperty &ndash;&gt;-->
<!-- <password>${env.NEXUS_PASSWORD}</password>-->
<!-- </authConfig>-->
<images>
<image>
<name>${registry.url}/${project.name}:${project.version}</name>
<registry>${registry.url}</registry>
<build>
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
<assembly>
<inline>
<files>
<file>
<source>
${project.basedir}/apm-agent/elastic-apm-agent-1.50.0.jar
</source>
<outputDirectory>.</outputDirectory>
</file>
<file>
<source>
${project.build.directory}/${project.build.finalName}.jar
</source>
<outputDirectory>.</outputDirectory>
</file>
<file>
<source>
${project.basedir}/src/main/resources/application.properties
</source>
<outputDirectory>.</outputDirectory>
</file>
</files>
</inline>
</assembly>
<tags>
<tag>${project.version}</tag>
</tags>
</build>
</image>
</images>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
<repository>
<id>mfd</id>
<name>mfd</name>
<url>http://10.200.200.131:8888/repository/internal/</url>
</repository>
</repositories>
</project>

View file

@ -0,0 +1,13 @@
package ru.nbch.indicsearchservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class IndicSearchServiceApplication {
public static void main(String[] args) {
SpringApplication.run(IndicSearchServiceApplication.class, args);
}
}

View file

@ -0,0 +1,30 @@
package ru.nbch.indicsearchservice.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MapperTimingAspect {
private static final Logger log = LoggerFactory.getLogger(MapperTimingAspect.class);
@Around("within(@org.apache.ibatis.annotations.Mapper *)")
public Object timeMapper(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
try {
return pjp.proceed();
} finally {
long tookMs = (System.nanoTime() - start) / 1_000_000;
String method = pjp.getSignature().toShortString();
if (tookMs > 1000) {
log.warn("Slow mapper call {} took {} ms", method, tookMs);
} else {
log.debug("Mapper call {} took {} ms", method, tookMs);
}
}
}
}

View file

@ -0,0 +1,50 @@
package ru.nbch.indicsearchservice.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@Aspect
@Component
public class TransactionLoggingAspect {
private static final Logger log = LoggerFactory.getLogger(TransactionLoggingAspect.class);
@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
public Object logTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
boolean newTransaction = !TransactionSynchronizationManager.isActualTransactionActive();
if (newTransaction) {
log.debug("Transaction STARTED: {}", joinPoint.getSignature());
}
if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void afterCommit() {
log.debug("Transaction COMMITTED: {}", joinPoint.getSignature());
}
@Override
public void afterCompletion(int status) {
if (status == STATUS_ROLLED_BACK) {
log.debug("Transaction ROLLED BACK: {}", joinPoint.getSignature());
}
}
}
);
}
try {
return joinPoint.proceed();
} catch (Exception ex) {
log.warn("Exception inside transaction: {}", joinPoint.getSignature(), ex);
throw ex;
}
}
}

View file

@ -0,0 +1,33 @@
package ru.nbch.indicsearchservice.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tools.jackson.core.StreamReadConstraints;
import tools.jackson.core.json.JsonFactory;
import tools.jackson.databind.MapperFeature;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.PropertyNamingStrategies;
import tools.jackson.databind.json.JsonMapper;
@Configuration
public class ObjectMapperConfig {
@Bean
public ObjectMapper objectMapper() {
JsonFactory factory = JsonFactory.builder()
.streamReadConstraints(StreamReadConstraints.builder()
.maxStringLength(100_000_000)
.build()
)
.build();
return JsonMapper.builder(factory)
.propertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true)
.changeDefaultPropertyInclusion(incl -> incl
.withContentInclusion(JsonInclude.Include.NON_NULL)
.withValueInclusion(JsonInclude.Include.NON_NULL))
.build();
}
}

View file

@ -0,0 +1,83 @@
package ru.nbch.indicsearchservice.config.datasource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import ru.nbch.indicsearchservice.config.settings.ApplicationSettings;
import ru.nbch.indicsearchservice.util.typehandler.NullableLocalDateTimeTypeHandler;
import ru.nbch.indicsearchservice.util.typehandler.NullableLocalDateTypeHandler;
@Configuration
@MapperScan(
basePackages = "ru.nbch.indicsearchservice.repository.bank",
sqlSessionFactoryRef = "bankSqlSessionFactory"
)
@Profile("!test")
public class DataSourceConfig {
private static final Logger log = LoggerFactory.getLogger(DataSourceConfig.class);
private final ApplicationSettings settings;
public DataSourceConfig(ApplicationSettings settings) {
this.settings = settings;
}
@Bean(name = "bankDataSource")
public DataSource dataSource() {
log.info("Connecting to bank database...");
HikariConfig config = new HikariConfig();
config.setDriverClassName(settings.getDataSource().getDriver());
config.setJdbcUrl(settings.getDataSource().getUrl());
config.setUsername(settings.getDataSource().getUsername());
config.setPassword(settings.getDataSource().getPassword());
config.setConnectionTimeout(settings.getDataSource().getConnectionTimeout());
config.setValidationTimeout(settings.getDataSource().getValidationTimeout());
config.setIdleTimeout(settings.getDataSource().getIdleTimeout());
config.setMaximumPoolSize(settings.getDataSource().getMaxPoolSize());
config.setMaxLifetime(settings.getDataSource().getMaxLifetime());
config.setKeepaliveTime(settings.getDataSource().getKeepAliveTime());
config.setPoolName("bank-database-pool");
return new HikariDataSource(config);
}
@Bean(name = "bankSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("bankDataSource") DataSource dataSource) throws Exception {
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true);
configuration.getTypeHandlerRegistry().register(LocalDate.class, JdbcType.DATE, new NullableLocalDateTypeHandler());
configuration.getTypeHandlerRegistry().register(LocalDateTime.class, JdbcType.TIMESTAMP, new NullableLocalDateTimeTypeHandler());
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setConfiguration(configuration);
sqlSessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:mappers/bank/*.xml")
);
return sqlSessionFactoryBean.getObject();
}
@Bean(name = "bankTransactionManager")
@Primary
public PlatformTransactionManager transactionManager(@Qualifier("bankDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}

View file

@ -0,0 +1,39 @@
package ru.nbch.indicsearchservice.config.datasource;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import ru.nbch.indicsearchservice.util.DataSourceUpdater;
@Configuration
public class IndicDataSourceConfig {
private static final Logger log = LoggerFactory.getLogger(IndicDataSourceConfig.class);
private final DataSourceUpdater dataSourceUpdater;
public IndicDataSourceConfig(DataSourceUpdater dataSourceUpdater) {
this.dataSourceUpdater = dataSourceUpdater;
}
@Bean(name = "indicDataSource")
public DataSource indicDataSource() {
log.info("Connecting to indic datasource...");
return dataSourceUpdater.getDataSource(DataSourceUpdater.DataSourceType.INDIC);
}
@Bean(name = "indicSqlSessionFactoryBean")
public SqlSessionFactory sqlSessionFactoryBean() {
return dataSourceUpdater.getSqlSessionFactory(DataSourceUpdater.DataSourceType.INDIC);
}
@Bean(name = "indicTransactionManager")
public PlatformTransactionManager transactionManager(@Qualifier("indicDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}

View file

@ -0,0 +1,42 @@
package ru.nbch.indicsearchservice.config.settings;
import java.io.File;
import java.nio.file.Path;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "app")
public class ApplicationSettings {
@NestedConfigurationProperty
private DataSourceSettings dataSource;
private DataSourceSettings indicDataSource = new DataSourceSettings();
private File storageDirectory = Path.of("/opt/app/indic-search-service-storage").toAbsolutePath().toFile();
public DataSourceSettings getDataSource() {
return dataSource;
}
public void setDataSource(DataSourceSettings dataSource) {
this.dataSource = dataSource;
}
public DataSourceSettings getIndicDataSource() {
return indicDataSource;
}
public void setIndicDataSource(DataSourceSettings indicDataSource) {
this.indicDataSource = indicDataSource;
}
public File getStorageDirectory() {
return storageDirectory;
}
public void setStorageDirectory(File storageDirectory) {
this.storageDirectory = storageDirectory;
}
}

View file

@ -0,0 +1,95 @@
package ru.nbch.indicsearchservice.config.settings;
public class DataSourceSettings {
private String username;
private String password;
private String url;
private String driver;
private Long connectionTimeout = 30_000L;
private Long validationTimeout = 5_000L;
private Long idleTimeout = 600_000L;
private Integer maxPoolSize = 100;
private Long maxLifetime = 60000L * 30;
private Long keepAliveTime = 60000L * 2;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public Long getConnectionTimeout() {
return connectionTimeout;
}
public void setConnectionTimeout(Long connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public Long getValidationTimeout() {
return validationTimeout;
}
public void setValidationTimeout(Long validationTimeout) {
this.validationTimeout = validationTimeout;
}
public Long getIdleTimeout() {
return idleTimeout;
}
public void setIdleTimeout(Long idleTimeout) {
this.idleTimeout = idleTimeout;
}
public Integer getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(Integer maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public Long getMaxLifetime() {
return maxLifetime;
}
public void setMaxLifetime(Long maxLifetime) {
this.maxLifetime = maxLifetime;
}
public Long getKeepAliveTime() {
return keepAliveTime;
}
public void setKeepAliveTime(Long keepAliveTime) {
this.keepAliveTime = keepAliveTime;
}
}

View file

@ -0,0 +1,110 @@
package ru.nbch.indicsearchservice.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
import java.util.Optional;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import ru.nbch.indicsearchservice.dto.request.AddSearchJobRequestDto;
import ru.nbch.indicsearchservice.dto.response.AddSearchJobResponseDto;
import ru.nbch.indicsearchservice.dto.response.JobStatusResponseDto;
import ru.nbch.indicsearchservice.exception.InternalException;
import ru.nbch.indicsearchservice.service.IndicSearchService;
import ru.nbch.indicsearchservice.service.SettingsService;
@RestController
@RequestMapping("/api/v1/")
public class IndicSearchController {
private final IndicSearchService indicSearchService;
private final SettingsService settingsService;
public IndicSearchController(IndicSearchService indicSearchService,
SettingsService settingsService) {
this.indicSearchService = indicSearchService;
this.settingsService = settingsService;
}
@Operation(summary = "Add new search job")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
content = {
@Content(mediaType = "application/json",
schema = @Schema(implementation = AddSearchJobResponseDto.class))
},
description = "Success")
})
@PostMapping("/add_search_job")
public AddSearchJobResponseDto addSearchJob(@RequestBody @Valid AddSearchJobRequestDto request) {
return indicSearchService.addSearchJob(request);
}
@Operation(summary = "Get job status")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
content = {
@Content(mediaType = "application/json",
schema = @Schema(implementation = JobStatusResponseDto.class))
},
description = "Success")
})
@GetMapping("/job_status/{id}")
public JobStatusResponseDto getJobStatus(@PathVariable("id") Long id) {
return indicSearchService.getJobStatus(id);
}
@Operation(summary = "Export data as JSON or EXCEL")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
content = {
@Content(mediaType = "application/json",
schema = @Schema(implementation = ResponseEntity.class))
},
description = "Success")
})
@GetMapping("/export/{id}")
public ResponseEntity<?> export(@PathVariable("id") Long id,
@RequestParam(name = "type", defaultValue = "JSON") String exportType) {
return indicSearchService.export(id, exportType);
}
@Operation(summary = "Update local service settings")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Success")
})
@GetMapping("/update_settings")
public void updateSettings() {
settingsService.updateLocalSettings();
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public InternalException handleValidationException(MethodArgumentNotValidException ex) {
FieldError fieldError = ex.getBindingResult().getFieldErrors().getFirst();
if (fieldError.getCodes() == null) {
return new InternalException("Internal Server Error");
}
return switch (Optional.of(fieldError.getCodes()).orElse(new String[]{""})[0]) {
case "NotNull.addSearchJobRequestDto.dataType" -> new InternalException("Data type should not be null");
case "NotNull.addSearchJobRequestDto.searchParameter" -> new InternalException("Search parameter should not be null");
case "NotBlank.addSearchJobRequestDto.searchValue" -> new InternalException("Search value should not be null");
case "NotBlank.addSearchJobRequestDto.memberCode" -> new InternalException("Member code should not be null");
case "Size.addSearchJobRequestDto.memberCode" -> new InternalException("Member code should contain at least 6 symbols");
default -> new InternalException("Internal Server Error");
};
}
}

View file

@ -0,0 +1,93 @@
package ru.nbch.indicsearchservice.dto.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.util.Objects;
import ru.nbch.indicsearchservice.model.enums.DataType;
import ru.nbch.indicsearchservice.model.enums.SearchParameter;
@Schema(description = "Add search job request data transfer object")
public class AddSearchJobRequestDto {
@Schema(description = "Data type", example = "GUTDF")
@NotNull
private DataType dataType;
@Schema(description = "Search parameter", example = "APPLICATION_NUMBER")
@NotNull
private SearchParameter searchParameter;
@Schema(description = "Search value", example = "1")
@NotBlank
private String searchValue;
@Schema(description = "Member code", example = "AAA000")
@NotBlank
@Size(min = 6)
private String memberCode;
public AddSearchJobRequestDto() {
}
public AddSearchJobRequestDto(DataType dataType, SearchParameter searchParameter, String searchValue, String memberCode) {
this.dataType = dataType;
this.searchParameter = searchParameter;
this.searchValue = searchValue;
this.memberCode = memberCode;
}
public DataType getDataType() {
return dataType;
}
public void setDataType(DataType dataType) {
this.dataType = dataType;
}
public SearchParameter getSearchParameter() {
return searchParameter;
}
public void setSearchParameter(SearchParameter searchParameter) {
this.searchParameter = searchParameter;
}
public String getSearchValue() {
return searchValue;
}
public void setSearchValue(String searchValue) {
this.searchValue = searchValue;
}
public String getMemberCode() {
return memberCode;
}
public void setMemberCode(String memberCode) {
this.memberCode = memberCode;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
AddSearchJobRequestDto that = (AddSearchJobRequestDto) o;
return dataType == that.dataType && searchParameter == that.searchParameter && Objects.equals(searchValue, that.searchValue) && Objects.equals(memberCode, that.memberCode);
}
@Override
public int hashCode() {
return Objects.hash(dataType, searchParameter, searchValue, memberCode);
}
@Override
public String toString() {
return "AddSearchJobRequestDto{" +
"dataType=" + dataType +
", searchParameter=" + searchParameter +
", searchValue='" + searchValue + '\'' +
", memberCode='" + memberCode + '\'' +
'}';
}
}

View file

@ -0,0 +1,46 @@
package ru.nbch.indicsearchservice.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.util.Objects;
@Schema(description = "Add search job response data transfer object")
public class AddSearchJobResponseDto {
@Schema(description = "Job id", example = "1")
@NotNull
private Long jobId;
public AddSearchJobResponseDto() {
}
public AddSearchJobResponseDto(Long jobId) {
this.jobId = jobId;
}
public Long getJobId() {
return jobId;
}
public void setJobId(Long jobId) {
this.jobId = jobId;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
AddSearchJobResponseDto that = (AddSearchJobResponseDto) o;
return Objects.equals(jobId, that.jobId);
}
@Override
public int hashCode() {
return Objects.hashCode(jobId);
}
@Override
public String toString() {
return "AddSearchJobResponseDto{" +
"jobId=" + jobId +
'}';
}
}

View file

@ -0,0 +1,45 @@
package ru.nbch.indicsearchservice.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Objects;
import ru.nbch.indicsearchservice.model.enums.JobStatus;
@Schema(description = "Job's status response data transfer object")
public class JobStatusResponseDto {
@Schema(description = "Job's status", example = "DONE")
private JobStatus status;
public JobStatusResponseDto() {
}
public JobStatusResponseDto(JobStatus status) {
this.status = status;
}
public JobStatus getStatus() {
return status;
}
public void setStatus(JobStatus status) {
this.status = status;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
JobStatusResponseDto that = (JobStatusResponseDto) o;
return status == that.status;
}
@Override
public int hashCode() {
return Objects.hashCode(status);
}
@Override
public String toString() {
return "JobStatusResponseDto{" +
"status=" + status +
'}';
}
}

View file

@ -0,0 +1,7 @@
package ru.nbch.indicsearchservice.event;
import ru.nbch.indicsearchservice.util.DataSourceUpdater;
public record DataSourceChangedEvent(DataSourceUpdater.DataSourceType dataSourceType) {
}

View file

@ -0,0 +1,10 @@
package ru.nbch.indicsearchservice.exception;
public class InternalException extends RuntimeException {
private final String message;
public InternalException(String message) {
super(message);
this.message = message;
}
}

View file

@ -0,0 +1,134 @@
package ru.nbch.indicsearchservice.model;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Objects;
public class LocalizationObject {
private Long id;
private Long version;
@Nullable
private String code;
@Nullable
private LocalDateTime dateCreated;
@Nullable
private LocalDateTime lastUpdated;
@Nullable
private String text;
@NotNull
private String loc = "*";
@NotNull
private Short relevance = (short) 1;
public LocalizationObject() {
}
public LocalizationObject(Long id, Long version, @Nullable String code, @Nullable LocalDateTime dateCreated, @Nullable LocalDateTime lastUpdated, @Nullable String text, String loc, Short relevance) {
this.id = id;
this.version = version;
this.code = code;
this.dateCreated = dateCreated;
this.lastUpdated = lastUpdated;
this.text = text;
this.loc = loc;
this.relevance = relevance;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
@Nullable
public String getCode() {
return code;
}
public void setCode(@Nullable String code) {
this.code = code;
}
@Nullable
public LocalDateTime getDateCreated() {
return dateCreated;
}
public void setDateCreated(@Nullable LocalDateTime dateCreated) {
this.dateCreated = dateCreated;
}
@Nullable
public LocalDateTime getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(@Nullable LocalDateTime lastUpdated) {
this.lastUpdated = lastUpdated;
}
@Nullable
public String getText() {
return text;
}
public void setText(@Nullable String text) {
this.text = text;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
public Short getRelevance() {
return relevance;
}
public void setRelevance(Short relevance) {
this.relevance = relevance;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
LocalizationObject that = (LocalizationObject) o;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
@Override
public String toString() {
return "LocalizationObject{" +
"id=" + id +
", version=" + version +
", code='" + code + '\'' +
", dateCreated=" + dateCreated +
", lastUpdated=" + lastUpdated +
", text='" + text + '\'' +
", loc='" + loc + '\'' +
", relevance=" + relevance +
'}';
}
}

View file

@ -0,0 +1,79 @@
package ru.nbch.indicsearchservice.model;
import jakarta.annotation.Nullable;
import java.util.Objects;
public class Settings {
private Long id;
@Nullable
private Long version;
@Nullable
private String name;
@Nullable
private String value;
public Settings() {
}
public Settings(Long id, Long version, String name, String value) {
this.id = id;
this.version = version;
this.name = name;
this.value = value;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Settings settings = (Settings) o;
return Objects.equals(id, settings.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
@Override
public String toString() {
return "Settings{" +
"id=" + id +
", version=" + version +
", name='" + name + '\'' +
", value='" + value + '\'' +
'}';
}
}

View file

@ -0,0 +1,7 @@
package ru.nbch.indicsearchservice.model.enums;
public enum DataType {
GUTDF,
RUTDF,
TUTDF
}

View file

@ -0,0 +1,8 @@
package ru.nbch.indicsearchservice.model.enums;
public enum JobStatus {
DONE,
IN_PROGRESS,
QUEUED,
FAILED
}

View file

@ -0,0 +1,13 @@
package ru.nbch.indicsearchservice.model.enums;
public enum SearchParameter {
UUID, // УИд счета
ACCT_NUM, // Номер счета
APPLICATION_NUMBER, // УИд заявки (only for GUTDF, RUTDF)
OLD_APP_NUM, // Номер заявки
PASSPORT, // Паспорт субъекта
OGRN, // ОГРН субъекта
FID, // FID субъекта
SERIAL_NUM_ACCT, // SERIAL_NUM счета (only for TUTDF)
SERIAL_NUM_APP, // SERIAL_NUM заявки (only for TUTDF)
}

View file

@ -0,0 +1,4 @@
package ru.nbch.indicsearchservice.repository;
public interface MyBatisRepository {
}

View file

@ -0,0 +1,17 @@
package ru.nbch.indicsearchservice.repository.bank;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import ru.nbch.indicsearchservice.model.LocalizationObject;
@Mapper
public interface LocalizationObjectMapper {
List<LocalizationObject> findByCode(String code);
List<LocalizationObject> findAllByCodes(@Param("codes") List<String> codes);
void insert(LocalizationObject localization);
void insertBatch(@Param("list") List<LocalizationObject> list);
}

View file

@ -0,0 +1,17 @@
package ru.nbch.indicsearchservice.repository.bank;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import ru.nbch.indicsearchservice.model.Settings;
@Mapper
public interface SettingsMapper {
Optional<Settings> findByName(@Param("name") String name);
List<Settings> findAllByNames(@Param("names") List<String> names);
Collection<Settings> findAll();
}

View file

@ -0,0 +1,178 @@
package ru.nbch.indicsearchservice.repository.indic;
import java.util.LinkedHashMap;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.cursor.Cursor;
import ru.nbch.indicsearchservice.repository.MyBatisRepository;
@Mapper
public interface IndicMapper extends MyBatisRepository {
List<LinkedHashMap<String, String>> getTableColumnsByTableNames(List<String> tables);
List<LinkedHashMap<String, Object>> findAllByAcctNumAndMemberCodeFromRuUid(String columns, String acctNum, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByAcctNumAndMemberCodeFromRuUidCursor(String columns, String acctNum, String memberCode);
List<LinkedHashMap<String, Object>> findAllByApplicationNumberAndMemberCodeFromRuApplication(String columns, String applicationNumber, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByApplicationNumberAndMemberCodeFromRuApplicationCursor(String columns, String applicationNumber, String memberCode);
Long countAllByApplicationNumberAndMemberCodeFromRuApplication(String applicationNumber, String memberCode);
List<LinkedHashMap<String, Object>> findAllByUuidFromRuUid(String columns, String uuid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByUuidFromRuUidCursor(String columns, String uuid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByOgrnFromId(String idNorm);
Cursor<LinkedHashMap<String, Object>> findAllByOgrnFromIdCursor(String idNorm);
List<String> findAllDistinctFidByOgrnFromId(String idNorm);
List<LinkedHashMap<String, Object>> findAllByOgrnTutdfFromId(String idNorm);
Cursor<LinkedHashMap<String, Object>> findAllByOgrnTutdfFromIdCursor(String idNorm);
List<String> findAllDistinctFidByOgrnTutdfFromId(String idNorm);
List<LinkedHashMap<String, Object>> findAllByPassportFromId(String idNorm);
Cursor<LinkedHashMap<String, Object>> findAllByPassportFromIdCursor(String idNorm);
List<String> findAllDistinctFidByPassportFromId(String idNorm);
List<LinkedHashMap<String, Object>> findAllByPassportTutdfFromId(String idNorm);
Cursor<LinkedHashMap<String, Object>> findAllByPassportTutdfFromIdCursor(String idNorm);
List<String> findAllDistinctFidByPassportTutdfFromId(String idNorm);
List<LinkedHashMap<String, Object>> findAllByOldAppNumFromRuApplication(String columns, String oldAppNum, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByOldAppNumFromRuApplicationCursor(String columns, String oldAppNum, String memberCode);
Long countAllByOldAppNumFromRuApplication(String oldAppNum, String memberCode);
List<LinkedHashMap<String, Object>> findAllByAcctNumFromAccount(String columns, String acctNum, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByAcctNumFromAccountCursor(String columns, String acctNum, String memberCode);
List<LinkedHashMap<String, Object>> findAllBySerialNumFromAccount(String columns, String serialNum, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllBySerialNumFromAccountCursor(String columns, String serialNum, String memberCode);
List<LinkedHashMap<String, Object>> findAllByUuidFromAccount(String columns, String uuid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByUuidFromAccountCursor(String columns, String uuid, String memberCode);
List<LinkedHashMap<String, Object>> findAllBySerialNumAndMemberCodeFromInformation(String columns, String serialNum, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllBySerialNumAndMemberCodeFromInformationCursor(String columns, String serialNum, String memberCode);
Long countAllBySerialNumAndMemberCodeFromInformation(String serialNum, String memberCode);
List<LinkedHashMap<String, Object>> findAllByAppNumAndMemberCodeFromInformation(String columns, String appNum, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByAppNumAndMemberCodeFromInformationCursor(String columns, String appNum, String memberCode);
Long countAllByAppNumAndMemberCodeFromInformation(String appNum, String memberCode);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuTrade(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuTradeCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAccountAmt(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAccountAmtCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuCoborrower(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuCoborrowerCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuPaymtCondition(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuPaymtConditionCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuOverallval(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuOverallvalCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAmendment(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAmendmentCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuFunddate(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuFunddateCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuArrear(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuArrearCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuDuearrear(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuDuearrearCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuPastduearrear(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuPastduearrearCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuPaymt(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuPaymtCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuMonthaverpaymt(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuMonthaverpaymtCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuSourcenonmonetoblig(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuSourcenonmonetobligCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuSubjectnonmonetoblig(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuSubjectnonmonetobligCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuCollateral(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuCollateralCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuGuarantor(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuGuarantorCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuIndepguarantor(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuIndepguarantorCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuCollatinsured(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuCollatinsuredCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuCollatrepay(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuCollatrepayCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuGuaranteerepay(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuGuaranteerepayCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuObligtermination(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuObligterminationCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuSubmithold(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuSubmitholdCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAcquirerlegal(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAcquirerlegalCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAcquirerindivid(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAcquirerindividCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuServiceco(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuServicecoCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuObligaccount(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuObligaccountCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuLegalrecord(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuLegalrecordCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuObligsrcbankrupt(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuObligsrcbankruptCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuObligsrcliquid(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuObligsrcliquidCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAmountInfo(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAmountInfoCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuContractTermsChanges(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuContractTermsChangesCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAllArrears(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromRuAllArrearsCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromAccountAmend(String columns, String accSerialNum, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromAccountAmendCursor(String columns, String accSerialNum, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromPayment(String columns, String accSerialNum, String memberCode, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromPaymentCursor(String columns, String accSerialNum, String memberCode, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromCollateral(String columns, String accSerialNum, String memberCode, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromCollateralCursor(String columns, String accSerialNum, String memberCode, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromGuarantor(String columns, String accSerialNum, String memberCode, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromGuarantorCursor(String columns, String accSerialNum, String memberCode, String fid);
List<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromBankGuarantee(String columns, String accSerialNum, String memberCode, String fid);
Cursor<LinkedHashMap<String, Object>> findAllByAccSerialNumAndFidFromBankGuaranteeCursor(String columns, String accSerialNum, String memberCode, String fid);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuUid(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuUidCursor(String columns, String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuUidWithoutRealMemberCode(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuUidWithoutRealMemberCodeCursor(String columns, String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuApplication(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuApplicationCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromRuApplication(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuObligparttake(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuObligparttakeCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromRuObligparttake(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuBankruptcy(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuBankruptcyCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromRuBankruptcyWithBlocks(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuSettled(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuSettledCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromRuSettled(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuOtherlegal(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuOtherlegalCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromRuOtherlegal(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuCapability(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuCapabilityCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromRuCapability(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuDebtBurdenInfo(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromRuDebtBurdenInfoCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromRuDebtBurdenInfo(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromAccount(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromAccountCursor(String columns, String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromInformation(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromInformationCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromInformation(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromBankruptcy(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromBankruptcyCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromBankruptcy(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromConsumerBankruptcy(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromConsumerBankruptcyCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromConsumerBankruptcy(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromLegal(String columns, String fid, String memberCode);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndMemberCodeFromLegalCursor(String columns, String fid, String memberCode);
Long countAllByFidAndMemberCodeFromLegal(String fid, String memberCode);
List<LinkedHashMap<String, Object>> findAllByFidAndParentSerialNumFromRuCollateralBlocks(String columns, String fid, String parentSerialNum);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndParentSerialNumFromRuCollateralBlocksCursor(String columns, String fid, String parentSerialNum);
List<LinkedHashMap<String, Object>> findAllByFidAndParentSerialNumFromRuBankruptcyBlocks(String columns, String fid, String parentSerialNum);
Cursor<LinkedHashMap<String, Object>> findAllByFidAndParentSerialNumFromRuBankruptcyBlocksCursor(String columns, String fid, String parentSerialNum);
List<LinkedHashMap<String, Object>> countAllRuUidChildTablesByAcctNum(String acctNum, String memberCode);
List<LinkedHashMap<String, Object>> countAllRuUidChildTablesByFid(String fid, String memberCode);
List<LinkedHashMap<String, Object>> countAllRuUidChildTablesByFidWithoutRealMemberCode(String fid, String memberCode);
List<LinkedHashMap<String, Object>> countAllRuUidChildTablesByUuid(String uuid, String memberCode);
List<LinkedHashMap<String, Object>> countAllAccountChildTablesByAcctNum(String acctNum, String memberCode);
List<LinkedHashMap<String, Object>> countAllAccountChildTablesByFid(String fid, String memberCode);
List<LinkedHashMap<String, Object>> countAllAccountChildTablesBySerialNum(String serialNum, String memberCode);
List<LinkedHashMap<String, Object>> countAllAccountChildTablesByUuid(String uuid, String memberCode);
}

View file

@ -0,0 +1,22 @@
package ru.nbch.indicsearchservice.service;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import ru.nbch.indicsearchservice.dto.request.AddSearchJobRequestDto;
import ru.nbch.indicsearchservice.dto.response.AddSearchJobResponseDto;
import ru.nbch.indicsearchservice.dto.response.JobStatusResponseDto;
@Service
public class IndicSearchService {
public AddSearchJobResponseDto addSearchJob(AddSearchJobRequestDto request) {
return null;
}
public JobStatusResponseDto getJobStatus(Long id) {
return null;
}
public ResponseEntity<?> export(Long id, String exportType) {
return null;
}
}

View file

@ -0,0 +1,70 @@
package ru.nbch.indicsearchservice.service;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import ru.nbch.indicsearchservice.config.settings.ApplicationSettings;
import ru.nbch.indicsearchservice.event.DataSourceChangedEvent;
import ru.nbch.indicsearchservice.model.Settings;
import ru.nbch.indicsearchservice.repository.bank.SettingsMapper;
import ru.nbch.indicsearchservice.util.DataSourceUpdater;
@Service
public class SettingsService {
private final SettingsMapper settingsMapper;
private final ApplicationSettings localSettings;
private final ApplicationEventPublisher publisher;
public SettingsService(SettingsMapper settingsMapper,
ApplicationSettings localSettings,
ApplicationEventPublisher publisher) {
this.settingsMapper = settingsMapper;
this.localSettings = localSettings;
this.publisher = publisher;
}
public String getSettingsValueByName(String name) {
return settingsMapper.findByName(name)
.orElseThrow(() -> new RuntimeException("Setting with key: " + name + " was not found in database!"))
.getValue();
}
public Map<String, Optional<String>> getSettingsValuesByNames(List<String> names) {
if (names == null || names.isEmpty()) {
return Map.of();
}
List<Settings> foundValues = settingsMapper.findAllByNames(names);
if (foundValues == null || foundValues.isEmpty()) {
return Map.of();
}
return foundValues.stream().collect(Collectors.toMap(Settings::getName, s -> Optional.ofNullable(s.getValue())));
}
public Optional<String> getOptionalSettingsValueByName(String name) {
return settingsMapper.findByName(name).map(Settings::getValue);
}
public void updateLocalSettings() {
Optional<String> newStorageDirectory = getOptionalSettingsValueByName("indic-search-service-storage"); // todo: change key
publisher.publishEvent(new DataSourceChangedEvent(DataSourceUpdater.DataSourceType.INDIC));
if (newStorageDirectory.isPresent()) {
try {
Files.createDirectories(Paths.get(newStorageDirectory.get()));
} catch (IOException e) {
throw new RuntimeException(e);
}
localSettings.setStorageDirectory(new File(newStorageDirectory.get()));
}
}
}

View file

@ -0,0 +1,228 @@
package ru.nbch.indicsearchservice.util;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.sql.DataSource;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import ru.nbch.indicsearchservice.config.settings.ApplicationSettings;
import ru.nbch.indicsearchservice.config.settings.DataSourceSettings;
import ru.nbch.indicsearchservice.event.DataSourceChangedEvent;
import ru.nbch.indicsearchservice.repository.MyBatisRepository;
import ru.nbch.indicsearchservice.repository.indic.IndicMapper;
import ru.nbch.indicsearchservice.service.SettingsService;
import ru.nbch.indicsearchservice.util.typehandler.NullableLocalDateTimeTypeHandler;
import ru.nbch.indicsearchservice.util.typehandler.NullableLocalDateTypeHandler;
@Component
public class DataSourceUpdater {
private static final Logger log = LoggerFactory.getLogger(DataSourceUpdater.class);
private final ApplicationSettings settings;
private final Map<DataSourceType, DataSourceData> dataSourceMap = new ConcurrentHashMap<>();
public DataSourceUpdater(ApplicationSettings settings, SettingsService settingsService) {
this.settings = settings;
buildSettings(DataSourceType.INDIC, settingsService, settings::setIndicDataSource);
dataSourceMap.put(
DataSourceType.INDIC,
new DataSourceData(new AtomicReference<>(null), new AtomicReference<>(null), new AtomicReference<>(null))
);
}
@EventListener
public void onDatabaseChanged(DataSourceChangedEvent event) {
log.info("Connection to datasource {} invalidated", event.dataSourceType());
if (!dataSourceMap.containsKey(event.dataSourceType())) {
log.error("Unknown datasource type {}", event.dataSourceType());
return;
}
DataSource oldDataSource = dataSourceMap.get(event.dataSourceType()).dataSourceRef().getAndSet(null);
if (oldDataSource instanceof HikariDataSource ds) {
ds.close();
}
dataSourceMap.get(event.dataSourceType()).sqlSessionFactoryRef().set(null);
dataSourceMap.get(event.dataSourceType()).mapperRef().set(null);
}
public DataSource getDataSource(DataSourceType dataSourceType) {
if (!dataSourceMap.containsKey(dataSourceType)) {
log.error("Unknown datasource type {}", dataSourceType);
return null;
}
return getComponent(dataSourceMap.get(dataSourceType).dataSourceRef(), () -> buildDataSource(dataSourceType), "DataSource");
}
public SqlSessionFactory getSqlSessionFactory(DataSourceType dataSourceType) {
if (!dataSourceMap.containsKey(dataSourceType)) {
log.error("Unknown datasource type {}", dataSourceType);
return null;
}
return getComponent(dataSourceMap.get(dataSourceType).sqlSessionFactoryRef(), () -> buildSqlSessionFactory(dataSourceType), "SqlSessionFactory");
}
public MyBatisRepository getMapper(DataSourceType dataSourceType) {
if (!dataSourceMap.containsKey(dataSourceType)) {
log.error("Unknown datasource type {}", dataSourceType);
return null;
}
return getComponent(dataSourceMap.get(dataSourceType).mapperRef(), () -> buildMapper(dataSourceType), "Mapper");
}
private <T> T getComponent(AtomicReference<T> ref, Supplier<T> builder, String componentName) {
T component = ref.get();
if (component == null) {
synchronized (ref) {
component = ref.get();
if (component == null) {
try {
component = builder.get();
ref.set(component);
log.info("{} created successfully", componentName);
} catch (Exception e) {
log.error("Failed to build {}", componentName, e);
}
}
}
}
return component;
}
private DataSource buildDataSource(DataSourceType dataSourceType) {
DataSourceSettings dataSourceSettings = switch (dataSourceType) {
case INDIC -> settings.getIndicDataSource();
};
if (dataSourceSettings == null) {
log.error("{} configuration is null", dataSourceType);
return null;
}
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDriverClassName(dataSourceSettings.getDriver());
hikariConfig.setJdbcUrl(dataSourceSettings.getUrl());
hikariConfig.setUsername(dataSourceSettings.getUsername());
hikariConfig.setPassword(dataSourceSettings.getPassword());
hikariConfig.setConnectionTimeout(dataSourceSettings.getConnectionTimeout());
hikariConfig.setValidationTimeout(dataSourceSettings.getValidationTimeout());
hikariConfig.setIdleTimeout(dataSourceSettings.getIdleTimeout());
hikariConfig.setMaximumPoolSize(dataSourceSettings.getMaxPoolSize());
hikariConfig.setMaxLifetime(dataSourceSettings.getMaxLifetime());
hikariConfig.setKeepaliveTime(dataSourceSettings.getKeepAliveTime());
hikariConfig.setPoolName(dataSourceType + "-pool");
if (Objects.equals(dataSourceSettings.getDriver(), "net.sourceforge.jtds.jdbc.Driver")) {
hikariConfig.setConnectionTestQuery("select 1");
}
return new HikariDataSource(hikariConfig);
}
private SqlSessionFactory buildSqlSessionFactory(DataSourceType dataSourceType) {
DataSource dataSource = getDataSource(dataSourceType);
try {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
Configuration configuration = new Configuration();
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCallSettersOnNulls(true);
configuration.getTypeHandlerRegistry()
.register(LocalDate.class, JdbcType.DATE, new NullableLocalDateTypeHandler());
configuration.getTypeHandlerRegistry()
.register(LocalDateTime.class, JdbcType.TIMESTAMP, new NullableLocalDateTimeTypeHandler());
sqlSessionFactoryBean.setConfiguration(configuration);
if (dataSourceType == DataSourceType.INDIC) {
sqlSessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mappers/indic/*.xml")
);
} else {
Class<?> mapperClass = getMapperClass(dataSourceType);
configuration.addMapper(mapperClass);
}
SqlSessionFactory sessionFactory = sqlSessionFactoryBean.getObject();
if (sessionFactory == null) {
throw new IllegalStateException("Failed to create SqlSessionFactory");
}
return sessionFactory;
} catch (Exception e) {
log.error("Failed to build SqlSessionFactory", e);
throw new RuntimeException("Failed to build SqlSessionFactory", e);
}
}
private <T extends MyBatisRepository> T buildMapper(DataSourceType dataSourceType) {
Class<?> mapperClass = getMapperClass(dataSourceType);
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(dataSourceType);
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
return (T) sqlSessionTemplate.getMapper(mapperClass);
}
private Class<?> getMapperClass(DataSourceType dataSourceType) {
return switch (dataSourceType) {
case INDIC -> IndicMapper.class;
};
}
private void buildSettings(DataSourceType dataSourceType, SettingsService settingsService, Consumer<DataSourceSettings> settingsConsumer) {
String key = switch (dataSourceType) {
case INDIC -> "indic";
};
DataSourceSettings dataSourceSettings = new DataSourceSettings();
dataSourceSettings.setDriver(settingsService.getSettingsValueByName("datasource." + key + ".driver"));
dataSourceSettings.setUrl(settingsService.getSettingsValueByName("datasource." + key + ".url"));
dataSourceSettings.setUsername(settingsService.getSettingsValueByName("datasource." + key + ".username"));
dataSourceSettings.setPassword(settingsService.getSettingsValueByName("datasource." + key + ".password"));
dataSourceSettings.setConnectionTimeout(Long.valueOf(settingsService.getOptionalSettingsValueByName("datasource." + key + ".connection-timeout").orElse("30000")));
dataSourceSettings.setValidationTimeout(Long.valueOf(settingsService.getOptionalSettingsValueByName("datasource." + key + ".validation-timeout").orElse("5000")));
dataSourceSettings.setIdleTimeout(Long.valueOf(settingsService.getOptionalSettingsValueByName("datasource." + key + ".idle-timeout").orElse("600000")));
dataSourceSettings.setMaxPoolSize(Integer.valueOf(settingsService.getOptionalSettingsValueByName("datasource." + key + ".max-pool-size").orElse("100")));
dataSourceSettings.setMaxLifetime(Long.valueOf(settingsService.getOptionalSettingsValueByName("datasource." + key + ".max-lifetime").orElse("1800000")));
dataSourceSettings.setKeepAliveTime(Long.valueOf(settingsService.getOptionalSettingsValueByName("datasource." + key + ".keep-alive-time").orElse("120000")));
settingsConsumer.accept(dataSourceSettings);
}
private record DataSourceData(AtomicReference<DataSource> dataSourceRef,
AtomicReference<SqlSessionFactory> sqlSessionFactoryRef,
AtomicReference<MyBatisRepository> mapperRef) {
}
public enum DataSourceType {
INDIC
}
}

View file

@ -0,0 +1,22 @@
package ru.nbch.indicsearchservice.util;
import org.springframework.stereotype.Component;
import ru.nbch.indicsearchservice.repository.MyBatisRepository;
import ru.nbch.indicsearchservice.repository.indic.IndicMapper;
@Component
public class MapperHolder {
private final DataSourceUpdater dataSourceUpdater;
public MapperHolder(DataSourceUpdater dataSourceUpdater) {
this.dataSourceUpdater = dataSourceUpdater;
}
public IndicMapper getIndicMapper() {
MyBatisRepository repository = dataSourceUpdater.getMapper(DataSourceUpdater.DataSourceType.INDIC);
if (repository instanceof IndicMapper indicMapper) {
return indicMapper;
}
return null;
}
}

View file

@ -0,0 +1,37 @@
package ru.nbch.indicsearchservice.util.typehandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
@MappedJdbcTypes(JdbcType.DATE)
public class NullableLocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime parameter, JdbcType jdbcType) throws SQLException {
ps.setTimestamp(i, Timestamp.valueOf(parameter));
}
@Override
public LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
Timestamp timestamp = rs.getTimestamp(columnName);
return timestamp != null ? timestamp.toLocalDateTime() : null;
}
@Override
public LocalDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Timestamp timestamp = rs.getTimestamp(columnIndex);
return timestamp != null ? timestamp.toLocalDateTime() : null;
}
@Override
public LocalDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Timestamp timestamp = cs.getTimestamp(columnIndex);
return timestamp != null ? timestamp.toLocalDateTime() : null;
}
}

View file

@ -0,0 +1,37 @@
package ru.nbch.indicsearchservice.util.typehandler;
import java.sql.CallableStatement;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
@MappedJdbcTypes(JdbcType.DATE)
public class NullableLocalDateTypeHandler extends BaseTypeHandler<LocalDate> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, LocalDate parameter, JdbcType jdbcType) throws SQLException {
ps.setDate(i, Date.valueOf(parameter));
}
@Override
public LocalDate getNullableResult(ResultSet rs, String columnName) throws SQLException {
Date date = rs.getDate(columnName);
return date != null ? date.toLocalDate() : null;
}
@Override
public LocalDate getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Date date = rs.getDate(columnIndex);
return date != null ? date.toLocalDate() : null;
}
@Override
public LocalDate getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Date date = cs.getDate(columnIndex);
return date != null ? date.toLocalDate() : null;
}
}

View file

@ -0,0 +1,15 @@
spring.application.name=indic-search-service
logging.level.org.springframework.boot.context.config=DEBUG
# Database properties
app.data-source.driver=com.ibm.db2.jcc.DB2Driver
app.data-source.username=ros9lk
app.data-source.password=ros9lk
app.data-source.url=jdbc:db2://10.230.227.21:2667/DEVSUPPL:currentSchema=ROS9LK;
app.data-source.connection-timeout=40000
app.data-source.validation-timeout=5000
app.data-source.idle-timeout=600000
app.data-source.max-pool-size=10
app.data-source.max-lifetime=1800000
app.data-source.keep-alive-time=120000

View file

@ -0,0 +1,66 @@
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./logs/indic-search-service.log</file>
<encoder>
<charset>UTF-8</charset>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%line - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>
./logs/indic-search-service.%i.log
</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>500MB</maxFileSize>
</triggeringPolicy>
</appender>
<appender name="FILE-ECS" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./logs/json/indic-search-service.log</file>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"service":{"name":"indic-search-service"}}</customFields>
<fieldNames>
<timestamp>@timestamp</timestamp>
<level>log.level</level>
<logger>log.logger</logger>
<thread>process.thread.name</thread>
<message>message</message>
</fieldNames>
<includeCallerData>true</includeCallerData>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>./logs/json/indic-search-service-json.%d{yyyy-MM-dd}.%i.gz
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>10</maxHistory>
</rollingPolicy>
</appender>
<root level="warn">
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
</root>
<root level="error">
<appender-ref ref="FILE-ECS"/>
</root>
<logger name="ru.nbch" level="debug" additivity="false">
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="org.hibernate.engine.jdbc.spi.SqlExceptionHelper" level="ERROR"/>
</configuration>

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ru.nbch.indicsearchservice.repository.bank.LocalizationObjectMapper">
<resultMap id="localizationObjectResultMap" type="ru.nbch.indicsearchservice.model.LocalizationObject">
<id column="ID" property="id"/>
<result column="VERSION" property="version"/>
<result column="CODE" property="code"/>
<result column="DATE_CREATED" property="dateCreated"
typeHandler="ru.nbch.indicsearchservice.util.typehandler.NullableLocalDateTimeTypeHandler"/>
<result column="LAST_UPDATED" property="lastUpdated"
typeHandler="ru.nbch.indicsearchservice.util.typehandler.NullableLocalDateTimeTypeHandler"/>
<result column="LOC" property="loc"/>
<result column="RELEVANCE" property="relevance"/>
<result column="TEXT" property="text"/>
</resultMap>
<sql id="baseSelect">
SELECT ID,
VERSION,
CODE,
DATE_CREATED,
LAST_UPDATED,
LOC,
RELEVANCE,
TEXT
FROM LOCALIZATION_OBJECT
</sql>
<select id="findByCode" resultMap="localizationObjectResultMap">
<include refid="baseSelect"/>
WHERE CODE = #{code}
WITH UR
</select>
<select id="findAllByCodes" resultMap="localizationObjectResultMap">
<include refid="baseSelect"/>
WHERE CODE IN
<foreach item='code' collection='codes' open='(' separator=',' close=')'>#{code}</foreach>
</select>
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO LOCALIZATION_OBJECT (VERSION,
CODE,
DATE_CREATED,
LAST_UPDATED,
LOC,
RELEVANCE,
TEXT)
VALUES (0,
#{code},
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
#{loc},
#{relevance},
#{text})
</insert>
<insert id="insertBatch" useGeneratedKeys="true" keyProperty="id">
INSERT INTO LOCALIZATION_OBJECT (VERSION,
CODE,
DATE_CREATED,
LAST_UPDATED,
LOC,
RELEVANCE,
TEXT)
VALUES
<foreach collection="list" item="l" separator=",">
(0,
#{l.code},
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,
#{l.loc},
#{l.relevance},
#{l.text})
</foreach>
</insert>
</mapper>

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ru.nbch.indicsearchservice.repository.bank.SettingsMapper">
<resultMap id="settingsResultMap" type="ru.nbch.indicsearchservice.model.Settings">
<id column="ID" property="id"/>
<result column="VERSION" property="version"/>
<result column="NAME" property="name"/>
<result column="VALUE" property="value"/>
</resultMap>
<sql id="baseSelect">
SELECT ID,
VERSION,
NAME,
"VALUE"
FROM SETTINGS
</sql>
<select id="findByName" resultMap="settingsResultMap">
<include refid="baseSelect"/>
where NAME = #{name}
WITH UR
</select>
<select id="findAllByNames" resultMap="settingsResultMap">
<include refid="baseSelect"/>
WHERE NAME IN
<foreach item='name' collection='names' open='(' separator=',' close=')'>#{name}</foreach>
</select>
<select id="findAll" resultMap="settingsResultMap">
<include refid="baseSelect"/>
WITH UR
</select>
</mapper>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
package ru.nbch.indicsearchservice;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class IndicSearchServiceApplicationTests {
@Test
void contextLoads() {
}
}