Compare commits

..

10 Commits

Author SHA1 Message Date
874b4df7a6 dfgh
Some checks failed
WEB karideo and rabbit/archidata/pipeline/head There was a failure building this commit
2023-01-10 23:19:04 +01:00
a0269cbca7 stupid hobbit
Some checks failed
WEB karideo and rabbit/archidata/pipeline/head There was a failure building this commit
2023-01-10 22:35:24 +01:00
fcbf051c10 upgrade builder docker
Some checks failed
WEB karideo and rabbit/archidata/pipeline/head There was a failure building this commit
2023-01-10 22:31:14 +01:00
a073a01111 qsdf 2023-01-10 00:47:25 +01:00
1942bb7aa3 sdfg 2023-01-10 00:16:33 +01:00
3967bdd3a0 sqdfg 2023-01-10 00:07:08 +01:00
74102aaacc test 2023-01-10 00:04:55 +01:00
a1be582891 test sub-docker 2023-01-10 00:02:11 +01:00
e0d97328b1 test auto_build 2023-01-09 23:54:14 +01:00
742eb37cce test 2023-01-08 21:02:52 +01:00
299 changed files with 3518 additions and 26206 deletions

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
<fileset name="all" enabled="true" check-config-name="Google Checks" local="false">
<file-match-pattern match-pattern="." include-pattern="true"/>
</fileset>
</fileset-config>

View File

@ -1,48 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry including="**/*.java" kind="src" output="target/classes" path="src">
<classpathentry kind="src" output="out/maven/classes" path="src">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="test/src">
<classpathentry kind="src" output="out/maven/test-classes" path="test/src">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="test/resources">
<attributes>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
<classpathentry kind="output" path="out/maven/classes"/>
</classpath>

View File

@ -1,12 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"

View File

@ -1,16 +0,0 @@
---
name: "Assign PR Author as Assignee"
on:
pull_request:
types:
- opened
jobs:
assign-pr-author-as-assignee:
runs-on: ubuntu-latest
steps:
- name: "Assign Author as Assignee"
uses: itsOliverBott/assign-pr-author-as-assignee@latest
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,33 +0,0 @@
---
name: "Check PR title"
on:
pull_request:
types:
- opened
- edited
- synchronize
- ready_for_review
- reopened
jobs:
check-title:
runs-on: ubuntu-latest
steps:
- name: "Check title"
uses: Slashgear/action-check-pr-title@v4.3.0
with:
regexp: "\\[(API,)?(API|DEV-OPS|DOC|FEAT|FIX|FIX\\-CI|STYLE)\\]( \\([A-Za-z0-9.\\-]+\\))? [A-Za-z0-9 ,.'\\-!]+$"
helpMessage: |
Title of the PR MUST respect format: "[{TYPE}] clear description without typos in english" with {TYPE}:
* [API] Change API that permit to access on the application (un-compatibility only). This one can specifically added with [API,{TYPE}]
* [DEV-OPS] Update automatic build system, method to deliver application/packages, ...
* [DOC] Update or add some documentation.
* [FEAT] Develop a new feature
* [FIX] When fixing issue
* [FIX-CI] When the CI fail to build and we apply a correction to set it work again.
* [STYLE] Update of the style tools/checker, or add/remove rules.
Examples:
[FEAT] My beautiful feature
[API,FIX] Change API to fix typo
[FIX] (module) Correct part of ...

View File

@ -1,35 +0,0 @@
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Java CI with Maven
on:
push:
branches:
- develop
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: find the element
run: find . -name "dependency-graph.json"
# Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
- name: Update dependency graph
uses: advanced-security/maven-dependency-submission-action@4f64ddab9d742a4806eeb588d238e4c311a8397d

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
out/
target/
*.class
.settings/

View File

@ -1,14 +0,0 @@
#!/bin/bash
version_file="version.txt"
# update the Maven version number
mvn versions:set -DnewVersion=$(sed 's/dev/SNAPSHOT/g' $version_file)
if grep -q "DEV" "$version_file"; then
# update all versions release of dependency
mvn versions:use-latest-releases
# update our manage dependency as snapshoot
mvn versions:use-latest-versions -Dincludes=kangaroo-and-rabbit
else
# update our manage dependency as release (must be done before)
mvn versions:use-latest-releases -Dincludes=kangaroo-and-rabbit
fi

View File

@ -1,5 +1,18 @@
pipeline {
agent any
//agent any
agent {
docker {
image 'gitea.atria-soft.org/kangaroo-and-rabbit/archlinux-builder:latest'
//args '-u root'
}
}
options {
timeout(time: 30, unit: 'MINUTES')
disableConcurrentBuilds abortPrevious: true
}
triggers {
cron(env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'dev' ? '0 10 * * *' : '')
}
environment {
REGISTRY_ADDRESS = "gitea.atria-soft.org"
REGISTRY_ADDRESS_FULL = "https://${REGISTRY_ADDRESS}"
@ -18,6 +31,11 @@ pipeline {
sh 'javac --version'
}
}
stage('(prod) Build') {
steps {
sh 'mvn install'
}
}
}
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>archi-data</name>
<name>achi-data</name>
<comment></comment>
<projects>
</projects>
@ -10,11 +10,6 @@
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
@ -24,17 +19,5 @@
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>edu.umd.cs.findbugs.plugin.eclipse.findbugsNature</nature>
</natures>
<filteredResources>
<filter>
<id>1682721079856</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

View File

@ -1,400 +1,365 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="23">
<profile kind="CodeFormatterProfile" name="EWOL" version="23">
<!DOCTYPE xml>
<profiles version="18">
<profile kind="CodeFormatterProfile" name="Scenarium" version="18">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="preserve_positions"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="200"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="33"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="200"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>

375
LICENSE
View File

@ -1,373 +1,6 @@
Mozilla Public License Version 2.0
==================================
PROPIETARY licence
==================
1. Definitions
--------------
Copyright at Edouard DUPIN
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.
you have no right

View File

@ -1,104 +1,25 @@
Archi-data
==========
Generic backend for archidata in java
===================================
Archi-data is a framework that simplify:
- Creating a REST server with:
- Right control
- Swagger display interface
- Normalize error generate by the server
- Access to the DB:
- introspect Object and insert in the TD (SQLITE & MY-SQL)
- Manage migration
- JPA checker for many generic request
- simplify the request of the Test-service
Develop in cmd-line:
--------------------
The first step is configuring your JAVA version (or select the JVM with the OS)
```bash
export PATH=$(ls -d --color=never /usr/lib/jvm/java-2*-openjdk)/bin:$PATH
```
Install the dependency:
```bash
mvn install
```
Run the test
```bash
mvn test
```
Install it for external use
```bash
mvn install
```
Develop With Eclipse:
--------------------
Import the project:
- Open a (new) project on eclipse
- `File` -> `Import`
- `Maven` -> `Existing Maven project`
- Select the `pom.xml` file and click on import
Run the Test:
- Open the package `test.kar.archidata`
- Click right on it
- Select `Debug As` -> `JUnit Test`
Install in the local maven repository:
- Click right on the `pom.xml` file
- Select `Run As` -> `Maven install`
// create a single package jar
mvn clean compile assembly:single
Somes tools:
============
Auto-update dependency:
-----------------------
generic interface for all KAR web application
Auto-update to the last version dependency:
auto-update to the last version dependency:
```bash
mvn versions:use-latest-versions
```
Format the code
---------------
Simply run the cmd-line:
```bash
mvn formatter:format
```
Reformat XML file like the pom.xml
```bash
XMLLINT_INDENT=" " xmllint --format "back/pom.xml" -o "back/pom.xml"
```
Enable the pre-commit checker
-----------------------------
```bash
./tools/configure_precommit.bash
```
> **_Note_**: You can change the code in `.git/hooks/pre-commit` by replacing `formatter:verify` with `formatter:format` to auto format the code @ every commit
Run Spot-bug:
------------
```bash
mvn spotbugs:check
```
Add Gitea in the dependency for the registry:
=============================================
@ -128,8 +49,8 @@ edit file: ```~/.m2/settings.xml```
release:
========
```bash
export PATH=$(ls -d --color=never /usr/lib/jvm/java-2*-openjdk)/bin:$PATH
```
export PATH=/usr/lib/jvm/java-18-openjdk/bin:$PATH
mvn install
mvn deploy
```

View File

@ -1 +0,0 @@

View File

@ -1,202 +0,0 @@
Wrapping over the DB
====================
In the current version we consider 2 DB access: MySQL and SQLite, We commonly use the SQLite in test mode to permit to test is a real case.
Generic Access:
---------------
Some generic function are available to permit you to simply request the DB
### Create a new Value:
```java
MyDataModel dataToInsert = ...;
MyDataModel dataCreated = DataAccess.insert(dataToInsert);
```
### Get a full table:
```java
List<MyDataModel> data = DataAccess.gets(MyDataModel.class);
```
### Get a single element in the DB:
```java
UUID id = ...;
MyDataModel data = DataAccess.get(MyDataModel.class, id);
```
> **_Note:_** The Id type fully managed are UUID and Long
### Removing the Data:
```java
UUID id = ...;
DataAccess.delete(MyDataModel.class, id);
```
> **_Note:_** Removing the data automatically detect if it is a software remove or definitive remove
### Updating the Data:
The update of the data can be managed by 2 way:
- Direct update of the Object with direct injection (Good for `PUT`)
- Update with input json (Good for `PATCH`)
The second way is preferable for some reasons
- When jakarta transform the data in you object, we can not detect the element set at null or not set (We consider user of `Optional` il all data class will create a too bug amount of unneeded code in all dev parts)
- Throw in the jakarta parsing are not well catch when we will generate generic error
- The Check will permit to explain what is wrong better than a generic Json parser.
Updating with JSON:
```java
UUID id = ...;
String jsonRequest = "{...}";
DataAccess.updateWithJson(MyDataModel.class, id, jsonRequest);
```
Updating with direct data:
```java
UUID id = ...;
MyDataModel dataToUpdate = ...;
// This update all fields:
DataAccess.update(dataToUpdate, id);
// Select the field to update:
DataAccess.update(dataToUpdate, id, List.of("field1","field2"));
```
Generic option of the request:
------------------------------
Many API have a generic multiple option available like:
```java
public static <T> List<T> getsWhere(final Class<T> clazz, final QueryOption... option) throws Exception
```
You just need to add your options in the list of `option`.
Filter the list of field read:
```java
public FilterValue(final String... filterValue)
public FilterValue(final List<String> filterValues)
// example:
new newFilterValue("field1", "field2");
```
Add a condition [more detail](#condition-models)
```java
public Condition(final QueryItem items)
```
Order the request:
```java
public OrderBy(final OrderItem... childs);
// example:
new OrderBy(new OrderItem("name", Order.DESC));
```
Limit the :
```java
public Limit(final long limit)
// example:
new Limit(50);
```
Read all column like update date and create date or delete field
```java
public ReadAllColumn()
```
Condition models:
-----------------
Creating a condition independent of the DB model use need to have a little abstraction of the query model:
For this we propose some condition that update with the internal "auto" condition that is added (like the soft delete...)
### default generic comparator
This is the base of the comparison tool. It compare a column with a value
```java
public QueryCondition(final String key, final String comparator, final Object value);
```
Simple DB comparison element. Note the injected object is injected in the statement and not in the query directly.
Example:
```java
String nameToCheck = "plop";
new QueryCondition("fieldName", "=", nameToCheck);
// OR:
UUID uuid = ...;
new QueryCondition("uuid", "=", uuid);
```
### List comparator
It permit to check a column is (NOT) in a list of value
```java
public QueryInList(final String key, final List<T> value)
public QueryInList(final String key, final T... value)
```
and his opposite:
```java
public QueryNotInList(final String key, final List<T> value)
public QueryNotInList(final String key, final T... value)
```
example
```java
new QueryInList("uuid", List.of(uuid1, uuid2));
```
### NULL and NOT NULL checker
This permit to check an element is `NULL` or `not NULL`
```java
public QueryNull(final String key);
public QueryNotNull(final String key);
```
### The group condition:
The generic `OR` group:
```java
public QueryOr(final List<QueryItem> child);
public QueryOr(final QueryItem... child);
```
Or the generic `AND group:
```java
public QueryAnd(final List<QueryItem> child);
public QueryAnd(final QueryItem... child);
```
### Full example:
```java
List<MyDataModel> result = DataAccess.getsWhere(MyDataModel.class,
new Limit(50),
new OrderBy(new OrderItem("name", Order.DESC)),
new Condition(
new QueryAnd(
QueryNull("Field3")
new QueryOr(
new QueryInList("Field4", 5, 55, 65, 62, 27, 84),
new QueryCondition("cityID", ">", 78000);
)
)
)
);
```

View File

@ -1,3 +0,0 @@
Basic tutorial
==============

View File

@ -1,16 +0,0 @@
Data Model
==========
The data model have 2 parts: the model of the DB and the model of the API. It is important to consider the 2 part due to the fact annotation will be manage by by a part, ot the other. Here we will study the Checking of the Data.
DB data model
=============
API data model
==============
Checking of the Data
====================

View File

@ -1,16 +0,0 @@
Archi-data documentation
========================
Archidata is base on generic Jakarta, grizzly and SQL or SQLite service.
It permit to simplify the interface of the server to concentrate on the API design.
Archi-data is a group of tools that manage some parts:
- [Wrapping over the DB](SQL_wrapper.md)
- [Data Model](data_model.md)
- [TypeScript Api generation](typescript_api_generation.md)
- [Migration tool](migration.md)
Some initialization tutorials:
- [Basic tutorial](TUTORIAL_01_first_install.md)

View File

@ -1,7 +0,0 @@
Migration tool
==============
Migration is a big part of the Server environment, it permit to migrate an old DB to a new one, and some tool permit the opposite.
Archi-data does not permit to do a reverse migration. I implement some code for it, but is was never tested. On my professional activity, we migrate only forward (Request if if really needed).

View File

@ -1,5 +0,0 @@
TypeScript Api generation
=========================

328
pom.xml
View File

@ -1,35 +1,38 @@
<?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>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.24.0</version>
<modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.2.4</version>
<properties>
<java.version>21</java.version>
<maven.compiler.version>3.1</maven.compiler.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.dependency.version>3.1.1</maven.dependency.version>
<jersey.version>3.1.5</jersey.version>
<jaxrs.version>2.1</jaxrs.version>
<jersey.version>2.32</jersey.version>
<jaxb.version>2.3.1</jaxb.version>
<istack.version>4.1.1</istack.version>
<istack.version>3.0.7</istack.version>
<maven.compiler.version>3.1</maven.compiler.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.dependency.version>3.1.1</maven.dependency.version>
</properties>
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
<snapshotRepository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</snapshotRepository>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
<snapshotRepository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</snapshotRepository>
</distributionManagement>
<dependencyManagement>
<dependencies>
<dependency>
@ -41,52 +44,13 @@
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.1.0-alpha1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.1.0-alpha1</version>
<scope>test</scope>
</dependency>
<!-- Decode webP images -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-webp</artifactId>
<version>3.11.0</version>
</dependency>
<!-- Decode JPEG image -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>3.11.0</version>
</dependency>
<!-- Encode file in webp -->
<dependency>
<groupId>com.github.gotson</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.2.2</version>
</dependency>
<!-- Detect type of a file with mime type -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>3.0.0-BETA2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-multipart -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
@ -101,14 +65,9 @@
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>4.0.0</version>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
@ -120,138 +79,48 @@
<artifactId>istack-commons-runtime</artifactId>
<version>${istack.version}</version>
</dependency>
<!-- continu to be needed ??? -->
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<scope>test</scope>
</dependency>
<!-- Serialize and un-serialize request in JSON-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.10</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>23.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.1</version>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.27</version>
</dependency>
<!-- encode output in CSV -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.18.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.1</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Interface for My-sql & sqlite DB -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.0.0</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.46.1.0</version>
</dependency>
<!-- Interface for JWT token -->
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.41.1</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</dependency>
<!-- Swagger dependencies -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-jakarta</artifactId>
<version>2.2.23</version>
</dependency>
<!-- spotbug tooling -->
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<version>4.8.6</version>
<scope>compile</scope>
</dependency>
<!-- Morphia -->
<dependency>
<groupId>dev.morphia.morphia</groupId>
<artifactId>morphia-core</artifactId>
<version>2.3.0</version>
</dependency>
<!-- MongoDB Java Driver -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.3.0</version>
</dependency>
<!-- Bean Validation (JSR 303 / 380) -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.0.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!--
************************************************************
** TEST dependency **
************************************************************
-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.24.1</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.5.0</version>
</dependency>
</dependencies>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>${basedir}/src/resources</directory>
</resource>
</resources>
<testSourceDirectory>test/src</testSourceDirectory>
<testResources>
<testResource>
<directory>${basedir}/test/resources</directory>
</testResource>
</testResources>
<directory>${project.basedir}/out/maven/</directory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -267,7 +136,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
@ -277,27 +145,13 @@
</execution>
</executions>
</plugin>
<!-- For dependabot plugin -->
<plugin>
<groupId>org.apache.servicemix.tooling</groupId>
<artifactId>depends-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<execution>
<id>generate-depends-file</id>
<goals>
<goal>generate-depends-file</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- junit results -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
<plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
@ -309,7 +163,7 @@
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugin>
<!-- Java-doc generation for stand-alone site -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -320,63 +174,6 @@
<nohelp>true</nohelp>
</configuration>
</plugin>
<!-- Check the style of the code -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<configLocation>CheckStyle.xml</configLocation>
<consoleOutput>true</consoleOutput>
<failOnViolation>true</failOnViolation>
<failsOnError>true</failsOnError>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
</plugin>
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.23.0</version>
<configuration>
<encoding>UTF-8</encoding>
<lineEnding>LF</lineEnding>
<configFile>Formatter.xml</configFile>
<directories>
<directory>src/</directory>
<directory>test/src</directory>
</directories>
<includes>
<include>**/*.java</include>
</includes>
<excludes>
<exclude>module-info.java</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>validate</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.5.0</version>
<configuration>
<includeFilterFile>spotbugs-security-include.xml</includeFilterFile>
<excludeFilterFile>spotbugs-security-exclude.xml</excludeFilterFile>
<!--<plugins>
<plugin>
<groupId>com.h3xstream.findsecbugs</groupId>
<artifactId>findsecbugs-plugin</artifactId>
<version>1.12.0</version>
</plugin>
</plugins>
-->
</configuration>
</plugin>
</plugins>
</build>
<!-- Generate Java-docs As Part Of Project Reports -->
@ -392,4 +189,5 @@
</plugin>
</plugins>
</reporting>
</project>
</project>

View File

@ -1,126 +0,0 @@
package sample.archidata.basic;
import java.net.URI;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.catcher.ExceptionCatcher;
import org.kar.archidata.catcher.FailExceptionCatcher;
import org.kar.archidata.catcher.InputExceptionCatcher;
import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.kar.archidata.db.DBConfig;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.tools.ConfigBaseVariable;
import sample.archidata.basic.api.Front;
import sample.archidata.basic.api.HealthCheck;
import sample.archidata.basic.api.MediaResource;
import sample.archidata.basic.api.SeasonResource;
import sample.archidata.basic.api.SeriesResource;
import sample.archidata.basic.api.TypeResource;
import sample.archidata.basic.api.UserMediaAdvancementResource;
import sample.archidata.basic.api.UserResource;
import sample.archidata.basic.filter.KarideoAuthenticationFilter;
import sample.archidata.basic.migration.Initialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.UriBuilder;
public class WebLauncher {
final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class);
public static DBConfig dbConfig;
protected UpdateJwtPublicKey keyUpdater = null;
protected HttpServer server = null;
public WebLauncher() {
ConfigBaseVariable.bdDatabase = "sample_archidata_basic";
}
private static URI getBaseURI() {
return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build();
}
public void migrateDB() throws Exception {
WebLauncher.LOGGER.info("Create migration engine");
final MigrationEngine migrationEngine = new MigrationEngine();
WebLauncher.LOGGER.info("Add initialization");
migrationEngine.setInit(new Initialization());
//WebLauncher.LOGGER.info("Add migration since last version");
//migrationEngine.add(new Migration20230810());
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(GlobalConfiguration.dbConfig);
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
}
public static void main(final String[] args) throws Exception {
WebLauncher.LOGGER.info("[START] application wake UP");
final WebLauncher launcher = new WebLauncher();
launcher.migrateDB();
launcher.process();
WebLauncher.LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
WebLauncher.LOGGER.info("STOP the REST server");
}
public void process() throws InterruptedException {
// ===================================================================
// Configure resources
// ===================================================================
final ResourceConfig rc = new ResourceConfig();
// Permit to accept OPTION request
rc.register(OptionFilter.class);
// remove cors ==> not obviously needed ...
rc.register(CORSFilter.class);
// register exception catcher (this permit to format return error with a normalized JSON)
rc.register(InputExceptionCatcher.class);
rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class);
rc.register(ExceptionCatcher.class);
// add default resource:
rc.register(MyModelResource.class);
// add jackson to be discover when we are in stand-alone server
rc.register(JacksonFeature.class);
this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc);
final HttpServer serverLink = this.server;
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
WebLauncher.LOGGER.info("Stopping server..");
serverLink.shutdownNow();
}
}, "shutdownHook"));
// ===================================================================
// run JERSEY
// ===================================================================
try {
this.server.start();
LOGGER.info("Jersey app started at {}", getBaseURI());
} catch (final Exception e) {
LOGGER.error("There was an error while starting Grizzly HTTP server.");
e.printStackTrace();
}
}
// This is used for TEST (See it later)
public void stop() {
if (this.server != null) {
this.server.shutdownNow();
this.server = null;
}
}
}

View File

@ -1,45 +0,0 @@
package sample.archidata.basic;
import java.util.List;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DataFactoryTsApi;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WebLauncherLocal extends WebLauncher {
private final static Logger LOGGER = LoggerFactory.getLogger(WebLauncherLocal.class);
private WebLauncherLocal() {}
public static void main(final String[] args) throws Exception {
final WebLauncherLocal launcher = new WebLauncherLocal();
launcher.process();
LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
LOGGER.info("STOP the REST server:");
}
@Override
public void process() throws InterruptedException {
if (true) {
// for local test:
ConfigBaseVariable.apiAddress = "http://0.0.0.0:9000/sample/api/";
ConfigBaseVariable.dbPort = "3906";
}
try {
super.migrateDB();
} catch (final Exception e) {
e.printStackTrace();
while (true) {
LOGGER.error("============================================================================");
LOGGER.error("== Migration fail ==> waiting intervention of administrator...");
LOGGER.error("============================================================================");
Thread.sleep(60 * 60 * 1000);
}
}
super.process();
}
}

View File

@ -1,79 +0,0 @@
package sample.archidata.basic.api;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.exception.FailException;
import org.kar.archidata.exception.InputException;
import org.kar.archidata.model.Data;
import org.kar.archidata.tools.DataTools;
import sample.archidata.basic.model.MyModel;
import sample.archidata.basic.model.Season;
import sample.archidata.basic.model.Series;
import sample.archidata.basic.model.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MyModelType;
@Path("/media")
@Produces(MyModelType.APPLICATION_JSON)
public class MyModelResource {
@GET
@PermitAll
public List<MyModel> gets() throws Exception {
return DataAccess.gets(MyModel.class);
}
@POST
@PermitAll
@Consumes(MyModelType.APPLICATION_JSON)
public MyModel create(final MyModel data) throws Exception {
return DataAccess.insert(data);
}
@GET
@Path("{id}")
@PermitAll
public MyModel get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(MyModel.class, id);
}
@PATCH
@Path("{id}")
@PermitAll
@Consumes(MyModelType.APPLICATION_JSON)
public MyModel patch(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
DataAccess.updateWithJson(MyModel.class, id, jsonRequest);
return DataAccess.get(MyModel.class, id);
}
@DELETE
@Path("{id}")
@PermitAll
public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(MyModel.class, id);
}
}

View File

@ -1,28 +0,0 @@
package sample.archidata.basic.migration;
import java.util.List;
import org.kar.archidata.migration.MigrationSqlStep;
import sample.archidata.basic.model.MyModel;
public class Initialization extends MigrationSqlStep {
public static final List<Class<?>> CLASSES_BASE = List.of(MyModel.class);
@Override
public String getName() {
return "Initialization";
}
@Override
public void generateStep() throws Exception {
for(final Class<?> clazz : CLASSES_BASE) {
addClass(clazz);
}
addAction("""
ALTER TABLE `MyModel` AUTO_INCREMENT = 1000;
""",
// Only MySql support this request (fail in SQLite)
"mysql");
}
}

View File

@ -1,36 +0,0 @@
package sample.archidata.basic.model;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
// needed for Swagger interface
@Entity
// Do not generate Null in Json serialization ==> prefer undefined
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MyModel extends GenericDataSoftDelete {
// Can not be NULL and max length is 300 (note default is 255)
@Column(nullable = false, length = 300)
public String name;
// Can be null and no max length
@Column(length = 0)
public String description;
@Override
public String toString() {
return "MyModel [name=" + this.name + ", description=" + this.description + "]";
}
}

View File

@ -1,5 +0,0 @@
<FindBugsFilter>
<Match>
<Bug category="SECURITY"/>
</Match>
</FindBugsFilter>

View File

@ -1,2 +0,0 @@
<FindBugsFilter>
</FindBugsFilter>

View File

@ -0,0 +1,16 @@
package org.kar.archidata;
import org.kar.archidata.db.DBConfig;
import org.kar.archidata.util.ConfigBaseVariable;
public class GlobalConfiguration {
public static DBConfig dbConfig = null;
static {
dbConfig = new DBConfig(ConfigBaseVariable.getDBHost(),
Integer.parseInt(ConfigBaseVariable.getDBPort()),
ConfigBaseVariable.getDBLogin(),
ConfigBaseVariable.getDBPassword(),
ConfigBaseVariable.getDBName());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +1,28 @@
package org.kar.archidata;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.JWTWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.kar.archidata.util.ConfigBaseVariable;
import org.kar.archidata.util.JWTWrapper;
public class UpdateJwtPublicKey extends Thread {
private static final Logger LOGGER = LoggerFactory.getLogger(UpdateJwtPublicKey.class);
boolean kill = false;
@Override
public void run() {
if (ConfigBaseVariable.getSSOAddress() == null) {
LOGGER.warn("SSO INTERFACE is not provided ==> work alone.");
// No SO provided, kill the thread.
return;
}
while (!this.kill) {
// need to upgrade when server call us...
while (this.kill == false) {
// need to uppgrade when server call us...
try {
JWTWrapper.initLocalTokenRemote(ConfigBaseVariable.getSSOAddress(), "archidata");
} catch (final Exception e1) {
} catch (Exception e1) {
e1.printStackTrace();
LOGGER.error("Can not retreive the basic tocken");
System.out.println("Can not retreive the basic tocken");
return;
}
try {
// update every 5 minutes the master token
Thread.sleep(1000 * 60 * 5, 0);
} catch (final InterruptedException e) {
Thread.sleep(1000*60*5, 0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void kill() {
this.kill = true;
}
}
}

View File

@ -0,0 +1,76 @@
package org.kar.archidata;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.model.User;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class UserDB {
public UserDB() {
}
public static User getUsers(long userId) throws Exception {
return SqlWrapper.get(User.class, userId);
}
public static User getUserOrCreate(long userId, String userLogin) throws Exception {
User user = getUsers(userId);
if (user != null) {
return user;
}
createUsersInfoFromOAuth(userId, userLogin);
return getUsers(userId);
}
private static void createUsersInfoFromOAuth(long userId, String login) throws IOException {
DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig);
String query = "INSERT INTO `user` (`id`, `login`, `lastConnection`, `admin`, `blocked`, `removed`) VALUE (?,?,now(3),'0','0','0')";
try {
PreparedStatement ps = entry.connection.prepareStatement(query);
ps.setLong(1, userId);
ps.setString(2, login);
ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
entry.close();
}
}
}

View File

@ -0,0 +1,8 @@
package org.kar.archidata;
public record WhereCondition(
String key,
String comparator,
Object Value) {
}

View File

@ -1,492 +0,0 @@
package org.kar.archidata.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.annotation.checker.Checker;
import org.kar.archidata.annotation.checker.CollectionItemNotNull;
import org.kar.archidata.annotation.checker.CollectionItemUnique;
import org.kar.archidata.annotation.checker.CollectionNotEmpty;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.options.OptionRenameColumn;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.morphia.annotations.Entity;
import dev.morphia.mapping.Mapper;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import jakarta.ws.rs.DefaultValue;
public class AnnotationTools {
static final Logger LOGGER = LoggerFactory.getLogger(AnnotationTools.class);
public static <TYPE extends Annotation> TYPE get(final Field element, final Class<TYPE> clazz) {
final TYPE[] annotations = element.getDeclaredAnnotationsByType(clazz);
if (annotations.length == 0) {
return null;
}
return annotations[0];
}
public static <TYPE extends Annotation> TYPE[] gets(final Field element, final Class<TYPE> clazz) {
final TYPE[] annotations = element.getDeclaredAnnotationsByType(clazz);
if (annotations.length == 0) {
return null;
}
return annotations;
}
// For SQL declaration table Name
public static String getTableName(final Class<?> clazz, final QueryOptions options) throws DataAccessException {
if (options != null) {
final List<OverrideTableName> data = options.get(OverrideTableName.class);
if (data.size() == 1) {
return data.get(0).getName();
}
}
return AnnotationTools.getTableName(clazz);
}
// For SQL declaration table Name
public static String getTableName(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Table.class);
if (annotation.length == 0) {
// when no annotation is detected, then the table name is the class name
return element.getSimpleName();
}
final String tmp = ((Table) annotation[0]).name();
if (tmp == null) {
return element.getSimpleName();
}
return tmp;
}
public static String getCollectionName(final Class<?> clazz, final QueryOptions options) {
if (options != null) {
// TODO: maybe change OverrideTableName with OverrideCollectionName
final List<OverrideTableName> data = options.get(OverrideTableName.class);
if (data.size() == 1) {
return data.get(0).getName();
}
}
return AnnotationTools.getCollectionName(clazz);
}
// For No-SQL Table/Collection Name
public static String getCollectionName(final Class<?> clazz) {
final Annotation[] annotation = clazz.getDeclaredAnnotationsByType(Entity.class);
if (annotation.length == 0) {
// when no annotation is detected, then the table name is the class name
return clazz.getSimpleName();
}
final String tmp = ((Entity) annotation[0]).value();
if (tmp == null || tmp.length() == 0 || Mapper.IGNORED_FIELDNAME.equals(tmp)) {
return clazz.getSimpleName();
}
return tmp;
}
public static CollectionItemNotNull getCollectionItemNotNull(final Field element) {
return get(element, CollectionItemNotNull.class);
}
public static CollectionItemUnique getCollectionItemUnique(final Field element) {
return get(element, CollectionItemUnique.class);
}
public static CollectionNotEmpty getCollectionNotEmpty(final Field element) {
return get(element, CollectionNotEmpty.class);
}
public static boolean getSchemaReadOnly(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return false;
}
return ((Schema) annotation[0]).readOnly();
}
public static String getSchemaExample(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
}
return ((Schema) annotation[0]).example();
}
public static boolean getNoWriteSpecificMode(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(NoWriteSpecificMode.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static String getSchemaDescription(final Class<?> element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
}
return ((Schema) annotation[0]).description();
}
public static String getSchemaDescription(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Schema.class);
if (annotation.length == 0) {
return null;
}
return ((Schema) annotation[0]).description();
}
public static String getDefault(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(DefaultValue.class);
if (annotation.length == 0) {
return null;
}
return ((DefaultValue) annotation[0]).value();
}
public static ManyToOne getManyToOne(final Field element) {
return get(element, ManyToOne.class);
}
public static ManyToMany getManyToMany(final Field element) {
return get(element, ManyToMany.class);
}
public static OneToMany getOneToMany(final Field element) {
return get(element, OneToMany.class);
}
public static DataJson getDataJson(final Field element) {
return get(element, DataJson.class);
}
public static Checker[] getConstraintsCheckers(final Field element) {
return gets(element, Checker.class);
}
public static DecimalMin getConstraintsDecimalMin(final Field element) {
return get(element, DecimalMin.class);
}
public static DecimalMax getConstraintsDecimalMax(final Field element) {
return get(element, DecimalMax.class);
}
public static Max getConstraintsMax(final Field element) {
return get(element, Max.class);
}
public static Min getConstraintsMin(final Field element) {
return get(element, Min.class);
}
public static int getLimitSize(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return 255;
}
final int length = ((Column) annotation[0]).length();
return length <= 0 ? 0 : length;
}
public static Size getConstraintsSize(final Field element) {
return get(element, Size.class);
}
public static Pattern getConstraintsPattern(final Field element) {
return get(element, Pattern.class);
}
public static Email getConstraintsEmail(final Field element) {
return get(element, Email.class);
}
public static boolean isAnnotationGroup(final Field field, final Class<?> annotationType) {
try {
final Annotation[] anns = field.getAnnotations();
for (final Annotation ann : anns) {
if (ann.annotationType() == annotationType) {
return true;
}
}
for (final Annotation ann : anns) {
final Annotation[] anns2 = ann.annotationType().getDeclaredAnnotations();
for (final Annotation ann2 : anns2) {
if (ann2.annotationType() == annotationType) {
return true;
}
}
}
} catch (final Exception ex) {
LOGGER.error("Catch exception when try to get annotation...{}", ex.getLocalizedMessage());
return false;
}
return false;
}
public static String getFieldNameRaw(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return element.getName();
}
final String name = ((Column) annotation[0]).name();
if (name.isBlank()) {
return element.getName();
}
return name;
}
public record FieldName(
String inStruct,
String inTable) {};
public static FieldName getFieldName(final Field element, final QueryOptions options) {
final String inStructName = getFieldNameRaw(element);
String inTableName = inStructName;
if (options != null) {
final List<OptionRenameColumn> renamesColumn = options.get(OptionRenameColumn.class);
for (final OptionRenameColumn rename : renamesColumn) {
if (rename.columnName.equals(inStructName)) {
inTableName = rename.colomnNewName;
LOGGER.trace("Detect overwrite of column name '{}' => '{}'", inStructName, inTableName);
break;
}
}
}
return new FieldName(inStructName, inTableName);
}
public static boolean getColumnNotNull(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return false;
}
return !((Column) annotation[0]).nullable();
}
public static boolean getNullable(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Nullable.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static boolean getConstraintsNotNull(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(NotNull.class);
if (annotation.length == 0) {
return false;
}
return true;
}
public static Field getPrimaryKeyField(final Class<?> clazz) {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.isPrimaryKey(field)) {
return field;
}
}
return null;
}
public static boolean isPrimaryKey(final Field element) {
final Annotation[] annotationSQL = element.getDeclaredAnnotationsByType(Id.class);
if (annotationSQL.length > 0) {
return true;
}
final Annotation[] annotationMongo = element.getDeclaredAnnotationsByType(dev.morphia.annotations.Id.class);
if (annotationMongo.length > 0) {
return true;
}
return false;
}
public static boolean isUnique(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(Column.class);
if (annotation.length == 0) {
return false;
}
return ((Column) annotation[0]).unique();
}
public static GenerationType getStrategy(final Field element) {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(GeneratedValue.class);
if (annotation.length == 0) {
return null;
}
return ((GeneratedValue) annotation[0]).strategy();
}
public static boolean isDeletedField(final Field element) {
return element.getDeclaredAnnotationsByType(DataDeleted.class).length != 0;
}
public static boolean isCreatedAtField(final Field element) {
return element.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
}
public static boolean isUpdateAtField(final Field element) {
return element.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
}
public static boolean isDefaultNotRead(final Field element) {
return element.getDeclaredAnnotationsByType(DataNotRead.class).length != 0;
}
public static boolean isIdField(final Field element) {
if (element.getDeclaredAnnotationsByType(Id.class).length != 0) {
return true;
}
return element.getDeclaredAnnotationsByType(dev.morphia.annotations.Id.class).length != 0;
}
// Note: delete field can not be renamed with OptionRenameColumn
public static String getDeletedFieldName(final Class<?> clazz) {
try {
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
if (AnnotationTools.isDeletedField(elem)) {
return AnnotationTools.getFieldNameRaw(elem);
}
}
} catch (final Exception ex) {
ex.printStackTrace();
}
return null;
}
// Note: update field can not be renamed with OptionRenameColumn
public static String getUpdatedFieldName(final Class<?> clazz) {
try {
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
if (AnnotationTools.isUpdateAtField(elem)) {
return AnnotationTools.getFieldNameRaw(elem);
}
}
} catch (final Exception ex) {
ex.printStackTrace();
}
return null;
}
public static Field getIdField(final Class<?> clazz) {
try {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.isIdField(field)) {
return field;
}
}
} catch (final Exception ex) {
ex.printStackTrace();
}
return null;
}
public static boolean hasFieldsName(final Class<?> clazz, final String name) {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.getFieldNameRaw(field).equals(name)) {
return true;
}
}
return false;
}
public static List<String> getFieldsNames(final Class<?> clazz) {
return getFieldsNamesFilter(clazz, false);
}
public static List<String> getAllFieldsNames(final Class<?> clazz) {
return getFieldsNamesFilter(clazz, true);
}
private static List<String> getFieldsNamesFilter(final Class<?> clazz, final boolean full) {
final List<String> out = new ArrayList<>();
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (!full && AnnotationTools.isGenericField(field)) {
continue;
}
out.add(AnnotationTools.getFieldNameRaw(field));
}
return out;
}
public static boolean isGenericField(final Field elem) {
return AnnotationTools.isPrimaryKey(elem) || AnnotationTools.isCreatedAtField(elem)
|| AnnotationTools.isUpdateAtField(elem) || AnnotationTools.isDeletedField(elem);
}
public static Field getFieldOfId(final Class<?> clazz) {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.isIdField(field)) {
return field;
}
}
return null;
}
public static Field getFieldNamed(final Class<?> clazz, final String name) {
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
if (AnnotationTools.getFieldNameRaw(field).equals(name)) {
return field;
}
}
return null;
}
}

View File

@ -1,17 +0,0 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** In case of the update parameter with String input to detect null element. */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface AsyncType {
// Possible class values.
Class<?>[] value();
// direct copy value in the TypeScript (separate with type by a |
String[] tsComplement() default {};
}

View File

@ -1,12 +0,0 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface FormDataOptional {
}

View File

@ -1,13 +0,0 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** When we wend to have only One type for read and write mode (Wrapping API). */
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NoWriteSpecificMode {
}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CreationTimestamp {
public @interface SQLAutoIncrement {
}

View File

@ -7,6 +7,8 @@ import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface DataJson {
Class<?> targetEntity() default Void.class;
public @interface SQLComment {
String value();
}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UpdateTimestamp {
public @interface SQLCreateTime {
}

View File

@ -1,4 +1,4 @@
package org.kar.archidata.annotation.checker;
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -7,6 +7,8 @@ import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckForeignKey {
Class<?> target();
public @interface SQLDefault {
String value();
}

View File

@ -0,0 +1,12 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLForeignKey {
String value();
}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataIfNotExists {
public @interface SQLIfNotExists {
}

View File

@ -0,0 +1,12 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLLimitSize {
int value();
}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataNotRead {
public @interface SQLNotNull {
}

View File

@ -7,6 +7,6 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataDeleted {
public @interface SQLNotRead {
}

View File

@ -0,0 +1,12 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLPrimaryKey {
}

View File

@ -0,0 +1,20 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLTableLinkGeneric {
public enum ModelLink {
NONE,
INTERNAL,
EXTERNAL
};
ModelLink value() default ModelLink.EXTERNAL;
}

View File

@ -0,0 +1,14 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLTableName {
String value();
}

View File

@ -0,0 +1,12 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLUpdateTime {
}

View File

@ -1,11 +0,0 @@
package org.kar.archidata.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** In case of the update parameter with String input to detect null element. */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeScriptProgress {}

View File

@ -1,12 +0,0 @@
package org.kar.archidata.annotation.addOn;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLTableExternalForeinKeyAsList {
}

View File

@ -1,14 +0,0 @@
package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.kar.archidata.dataAccess.options.CheckFunctionInterface;
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Checker {
Class<? extends CheckFunctionInterface> value();
}

View File

@ -1,12 +0,0 @@
package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CollectionItemNotNull {
}

View File

@ -1,12 +0,0 @@
package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CollectionItemUnique {
}

View File

@ -1,12 +0,0 @@
package org.kar.archidata.annotation.checker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CollectionNotEmpty {
}

View File

@ -1,19 +0,0 @@
package org.kar.archidata.annotation.method;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.HttpMethod;
/**
* Indicates that the annotated method responds to HTTP ARCHIVE requests.
*
* @author Edouard DUPIN
* @see HttpMethod
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("ARCHIVE")
public @interface ARCHIVE {}

View File

@ -1,19 +0,0 @@
package org.kar.archidata.annotation.method;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.ws.rs.HttpMethod;
/**
* Indicates that the annotated method responds to HTTP RESTORE requests.
*
* @author Edouard DUPIN
* @see HttpMethod
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("RESTORE")
public @interface RESTORE {}

View File

@ -0,0 +1,14 @@
package org.kar.archidata.annotation.security;
import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@NameBinding
@Retention(RUNTIME)
@Target({METHOD})
public @interface DenyAll {
}

View File

@ -0,0 +1,14 @@
package org.kar.archidata.annotation.security;
import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@NameBinding
@Retention(RUNTIME)
@Target({METHOD})
public @interface PermitAll {
}

View File

@ -1,14 +1,14 @@
package org.kar.archidata.annotation.security;
import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import jakarta.ws.rs.NameBinding;
@NameBinding
@Retention(RUNTIME)
@Target({ METHOD })
public @interface PermitTokenInURI {}
@Target({METHOD})
public @interface PermitTokenInURI {
}

View File

@ -0,0 +1,15 @@
package org.kar.archidata.annotation.security;
import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@NameBinding
@Retention(RUNTIME)
@Target({METHOD})
public @interface RolesAllowed {
String[] value();
}

View File

@ -1,523 +1,428 @@
package org.kar.archidata.api;
import java.awt.Graphics2D;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.Data;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.util.ConfigBaseVariable;
import javax.imageio.ImageIO;
import javax.ws.rs.*;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.StreamingOutput;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.UUID;
import javax.imageio.ImageIO;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.exception.FailException;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.Data;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.CacheControl;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.StreamingOutput;
// https://stackoverflow.com/questions/35367113/jersey-webservice-scalable-approach-to-download-file-and-reply-to-client
// https://gist.github.com/aitoroses/4f7a2b197b732a6a691d
@Path("/data")
@Produces(MediaType.APPLICATION_JSON)
@Produces({MediaType.APPLICATION_JSON})
public class DataResource {
private static final Logger LOGGER = LoggerFactory.getLogger(DataResource.class);
private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks
/** Upload some datas */
private static long tmpFolderId = 1;
private final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
private final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks
/**
* Upload some datas
*/
private static long tmpFolderId = 1;
private static void createFolder(final String path) throws IOException {
if (!Files.exists(java.nio.file.Path.of(path))) {
// Log.print("Create folder: " + path);
Files.createDirectories(java.nio.file.Path.of(path));
}
}
private static void createFolder(String path) throws IOException {
if (!Files.exists(java.nio.file.Path.of(path))) {
//Log.print("Create folder: " + path);
Files.createDirectories(java.nio.file.Path.of(path));
}
}
public static long getTmpDataId() {
return tmpFolderId++;
}
public static long getTmpDataId() {
return tmpFolderId++;
}
public static String getTmpFileInData(final long tmpFolderId) {
final String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (final IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getTmpFileInData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getFileDataOld(final UUID uuid) {
final String stringUUID = uuid.toString();
final String part1 = stringUUID.substring(0, 2);
final String part2 = stringUUID.substring(2, 4);
final String part3 = stringUUID.substring(4);
final String finalPath = part1 + File.separator + part2;
String filePath = ConfigBaseVariable.getMediaDataFolder() + "_uuid" + File.separator + finalPath
+ File.separator;
try {
createFolder(filePath);
} catch (final IOException e) {
e.printStackTrace();
}
filePath += part3;
return filePath;
}
public static String getFileData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getFileData(final ObjectId oid) {
final String stringOid = oid.toHexString();
String dir1 = stringOid.substring(0, 2);
String dir2 = stringOid.substring(2, 4);
String dir3 = stringOid.substring(4, 6);
try {
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
final byte[] hashBytes = digest.digest(oid.toByteArray());
dir1 = String.format("%02x", hashBytes[0]);
dir2 = String.format("%02x", hashBytes[1]);
dir3 = String.format("%02x", hashBytes[2]);
} catch (final NoSuchAlgorithmException ex) {
LOGGER.error("Fail to generate the hash of the objectId ==> ise direct value ... {}", ex.getMessage());
}
final String finalPath = dir1 + File.separator + dir2 + File.separator + dir3;
String filePath = ConfigBaseVariable.getMediaDataFolder() + "_oid" + File.separator + finalPath
+ File.separator;
try {
createFolder(filePath);
} catch (final IOException e) {
e.printStackTrace();
}
filePath += stringOid;
return filePath;
}
public static String getFileMetaData(final ObjectId oid) {
return getFileData(oid) + ".json";
}
public Data getWithSha512(final String sha512) {
LOGGER.info("find sha512 = {}", sha512);
try {
return DataAccess.getWhere(Data.class, new Condition(new QueryCondition("sha512", "=", sha512)));
} catch (final Exception e) {
public static Data getWithSha512(String sha512) {
System.out.println("find sha512 = " + sha512);
try {
return SqlWrapper.getWhere(Data.class, "sha512", "=", sha512);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
return null;
}
public Data getWithId(final long id) {
LOGGER.info("find id = {}", id);
try {
return DataAccess.get(Data.class, id);
} catch (final Exception e) {
public static Data getWithId(long id) {
System.out.println("find id = " + id);
try {
return SqlWrapper.get(Data.class, id);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
return null;
}
public Data createNewData(final long tmpUID, final String originalFileName, final String sha512)
throws IOException {
// determine mime type:
Data injectedData = new Data();
String mimeType = "";
final String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
mimeType = switch (extension.toLowerCase()) {
case "jpg", "jpeg" -> "image/jpeg";
case "png" -> "image/png";
case "webp" -> "image/webp";
case "mka" -> "audio/x-matroska";
case "mkv" -> "video/x-matroska";
case "webm" -> "video/webm";
default -> throw new IOException("Can not find the mime type of data input: '" + extension + "'");
};
injectedData.mimeType = mimeType;
injectedData.sha512 = sha512;
final String tmpPath = getTmpFileInData(tmpUID);
injectedData.size = Files.size(Paths.get(tmpPath));
public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException {
// determine mime type:
Data injectedData = new Data();
String mimeType = "";
String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
switch (extension.toLowerCase()) {
case "jpg":
case "jpeg":
mimeType = "image/jpeg";
break;
case "png":
mimeType = "image/png";
break;
case "webp":
mimeType = "image/webp";
break;
case "mka":
mimeType = "audio/x-matroska";
break;
case "mkv":
mimeType = "video/x-matroska";
break;
case "webm":
mimeType = "video/webm";
break;
default:
throw new IOException("Can not find the mime type of data input: '" + extension + "'");
}
injectedData.mimeType = mimeType;
injectedData.sha512 = sha512;
String tmpPath = getTmpFileInData(tmpUID);
injectedData.size = Files.size(Paths.get(tmpPath));
try {
injectedData = DataAccess.insert(injectedData);
} catch (final Exception e) {
try {
injectedData = SqlWrapper.insert(injectedData);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
final String mediaPath = getFileData(injectedData.oid);
LOGGER.info("src = {}", tmpPath);
LOGGER.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
LOGGER.info("Move done");
return injectedData;
}
String mediaPath = getFileData(injectedData.id);
System.out.println("src = " + tmpPath);
System.out.println("dst = " + mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
System.out.println("Move done");
return injectedData;
}
public static void modeFileOldModelToNewModel(final UUID uuid, final ObjectId oid) throws IOException {
String mediaCurentPath = getFileDataOld(uuid);
String mediaDestPath = getFileData(oid);
LOGGER.info("src = {}", mediaCurentPath);
LOGGER.info("dst = {}", mediaDestPath);
if (Files.exists(Paths.get(mediaCurentPath))) {
LOGGER.info("move: {} ==> {}", mediaCurentPath, mediaDestPath);
Files.move(Paths.get(mediaCurentPath), Paths.get(mediaDestPath), StandardCopyOption.ATOMIC_MOVE);
}
// Move old meta-data...
mediaCurentPath = mediaCurentPath.substring(mediaCurentPath.length() - 4) + "meta.json";
mediaDestPath = mediaCurentPath.substring(mediaDestPath.length() - 4) + "meta.json";
if (Files.exists(Paths.get(mediaCurentPath))) {
LOGGER.info("moveM: {} ==> {}", mediaCurentPath, mediaDestPath);
Files.move(Paths.get(mediaCurentPath), Paths.get(mediaDestPath), StandardCopyOption.ATOMIC_MOVE);
}
LOGGER.info("Move done");
}
public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) {
return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData));
}
public static String saveTemporaryFile(final InputStream uploadedInputStream, final long idData)
throws FailException {
return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData));
}
public static void removeTemporaryFile(long idData) {
String filepath = DataResource.getTmpFileInData(idData);
if (Files.exists(Paths.get(filepath))) {
try {
Files.delete(Paths.get(filepath));
} catch (IOException e) {
System.out.println("can not delete temporary file : " + Paths.get(filepath));
e.printStackTrace();
}
}
}
public static void removeTemporaryFile(final long idData) {
final String filepath = DataResource.getTmpFileInData(idData);
if (Files.exists(Paths.get(filepath))) {
try {
Files.delete(Paths.get(filepath));
} catch (final IOException e) {
LOGGER.info("can not delete temporary file : {}", Paths.get(filepath));
e.printStackTrace();
}
}
}
// save uploaded file to a defined location on the server
static String saveFile(InputStream uploadedInputStream, String serverLocation) {
String out = "";
try {
OutputStream outpuStream = new FileOutputStream(new File(
serverLocation));
int read = 0;
byte[] bytes = new byte[CHUNK_SIZE_IN];
MessageDigest md = MessageDigest.getInstance("SHA-512");
// save uploaded file to a defined location on the server
static String saveFile(final InputStream uploadedInputStream, final String serverLocation) throws FailException {
String out = "";
MessageDigest md = null;
try (OutputStream outpuStream = new FileOutputStream(new File(serverLocation))) {
md = MessageDigest.getInstance("SHA-512");
} catch (final IOException ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Can not write in temporary file", ex);
} catch (final NoSuchAlgorithmException ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Can not find sha512 algorithms", ex);
}
if (md != null) {
try (OutputStream outpuStream = new FileOutputStream(new File(serverLocation))) {
int read = 0;
final byte[] bytes = new byte[CHUNK_SIZE_IN];
while ((read = uploadedInputStream.read(bytes)) != -1) {
// logger.info("write {}", read);
md.update(bytes, 0, read);
outpuStream.write(bytes, 0, read);
}
LOGGER.info("Flush input stream ... {}", serverLocation);
outpuStream.flush();
// create the end of sha512
final byte[] sha512Digest = md.digest();
// convert in hexadecimal
out = bytesToHex(sha512Digest);
uploadedInputStream.close();
} catch (final IOException ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Can not write in temporary file", ex);
}
}
return out;
}
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
//System.out.println("write " + read);
md.update(bytes, 0, read);
outpuStream.write(bytes, 0, read);
}
System.out.println("Flush input stream ... " + serverLocation);
System.out.flush();
outpuStream.flush();
outpuStream.close();
// create the end of sha512
byte[] sha512Digest = md.digest();
// convert in hexadecimal
out = bytesToHex(sha512Digest);
uploadedInputStream.close();
} catch (IOException ex) {
System.out.println("Can not write in temporary file ... ");
ex.printStackTrace();
} catch (NoSuchAlgorithmException ex) {
System.out.println("Can not find sha512 algorithms");
ex.printStackTrace();
}
return out;
}
public static String bytesToHex(final byte[] bytes) {
final StringBuilder sb = new StringBuilder();
for (final byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public Data getSmall(final ObjectId oid) {
try {
return DataAccess.get(Data.class, oid);
} catch (final Exception e) {
public Data getSmall(Long id) {
try {
return SqlWrapper.get(Data.class, id);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
return null;
}
@POST
@Path("/upload/")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@RolesAllowed("ADMIN")
@Operation(description = "Insert a new data in the data environment", tags = "SYSTEM")
public void uploadFile(
@Context final SecurityContext sc,
@FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) throws FailException {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.info("===================================================");
LOGGER.info("== DATA uploadFile {}", (gc == null ? "null" : gc.userByToken));
LOGGER.info("===================================================");
// public NodeSmall uploadFile(final FormDataMultiPart form) {
LOGGER.info("Upload file: ");
final String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (final IOException ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR,
"Impossible to create the folder in the server", ex);
}
saveFile(fileInputStream, filePath);
}
@POST
@Path("/upload/")
@Consumes({MediaType.MULTIPART_FORM_DATA})
@RolesAllowed("ADMIN")
public Response uploadFile(@Context SecurityContext sc, @FormDataParam("file") InputStream fileInputStream, @FormDataParam("file") FormDataContentDisposition fileMetaData) {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
System.out.println("===================================================");
System.out.println("== DATA uploadFile " + (gc==null?"null":gc.user));
System.out.println("===================================================");
//public NodeSmall uploadFile(final FormDataMultiPart form) {
System.out.println("Upload file: ");
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
e.printStackTrace();
}
saveFile(fileInputStream, filePath);
return Response.ok("Data uploaded successfully !!").build();
//return null;
}
@GET
@Path("{oid}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Operation(description = "Get back some data from the data environment", tags = "SYSTEM")
public Response retrieveDataId(
@Context final SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range,
@PathParam("oid") final ObjectId oid) throws FailException {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("===================================================");
LOGGER.info("== DATA retrieveDataId ? oid={} user={}", oid, (gc == null ? "null" : gc.userByToken));
// logger.info("===================================================");
final Data value = getSmall(oid);
if (value == null) {
return Response.status(404).entity("media NOT FOUND: " + oid).type("text/plain").build();
}
try {
return buildStream(getFileData(oid), range,
value.mimeType == null ? "application/octet-stream" : value.mimeType);
} catch (final Exception ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to build output stream", ex);
}
}
@GET
@Path("{id}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveDataId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
//System.out.println("===================================================");
System.out.println("== DATA retriveDataId ? id=" + id + " user=" + (gc==null?"null":gc.user));
//System.out.println("===================================================");
Data value = getSmall(id);
if (value == null) {
Response.status(404).
entity("media NOT FOUND: " + id).
type("text/plain").
build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
}
@GET
@Path("thumbnail/{oid}")
@RolesAllowed("USER")
@PermitTokenInURI
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Operation(description = "Get a thumbnail of from the data environment (if resize is possible)", tags = "SYSTEM")
// @CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retrieveDataThumbnailId(
@Context final SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range,
@PathParam("oid") final ObjectId oid) throws FailException {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.info("===================================================");
LOGGER.info("== DATA retrieveDataThumbnailId ? {}", (gc == null ? "null" : gc.userByToken));
LOGGER.info("===================================================");
final Data value = getSmall(oid);
if (value == null) {
return Response.status(404).entity("media NOT FOUND: " + oid).type("text/plain").build();
}
final String filePathName = getFileData(oid);
final File inputFile = new File(filePathName);
if (!inputFile.exists()) {
return Response.status(404).entity("{\"error\":\"media Does not exist: " + oid + "\"}")
.type("application/json").build();
}
if (value.mimeType.contentEquals("image/jpeg") || value.mimeType.contentEquals("image/png")
// || value.mimeType.contentEquals("image/webp")
) {
// reads input image
BufferedImage inputImage;
try {
inputImage = ImageIO.read(inputFile);
} catch (final IOException ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to READ the image", ex);
}
LOGGER.info("input size image: {}x{} type={}", inputImage.getWidth(), inputImage.getHeight(),
inputImage.getType());
final int scaledWidth = 250;
final int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth()
* scaledWidth);
@GET
@Path("thumbnail/{id}")
@RolesAllowed("USER")
@PermitTokenInURI
@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retriveDataThumbnailId(@Context SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) String token,
@HeaderParam("Range") String range,
@PathParam("id") Long id) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
//System.out.println("===================================================");
//System.out.println("== DATA retriveDataThumbnailId ? " + (gc==null?"null":gc.user));
//System.out.println("===================================================");
Data value = getSmall(id);
if (value == null) {
return Response.status(404).
entity("media NOT FOUND: " + id).
type("text/plain").
build();
}
String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data";
File inputFile = new File(filePathName);
if (!inputFile.exists()) {
return Response.status(404).
entity("{\"error\":\"media Does not exist: " + id + "\"}").
type("application/json").
build();
}
if ( value.mimeType.contentEquals("image/jpeg")
|| value.mimeType.contentEquals("image/png")
// || value.mimeType.contentEquals("image/webp")
) {
// reads input image
BufferedImage inputImage = ImageIO.read(inputFile);
int scaledWidth = 250;
int scaledHeight = (int)((float)inputImage.getHeight() / (float)inputImage.getWidth() * (float) scaledWidth);
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth,
scaledHeight, inputImage.getType());
// creates output image
final BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType());
// scales the input image to the output image
final Graphics2D g2d = outputImage.createGraphics();
LOGGER.info("output size image: {}x{}", scaledWidth, scaledHeight);
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
for (final String data : ImageIO.getWriterFormatNames()) {
LOGGER.info("availlable format: {}", data);
}
// create the output stream:
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// TODO: check how to remove buffer file !!! here, it is not needed at all...
//ImageIO.write(outputImage, "JPEG", baos);
//ImageIO.write(outputImage, "png", baos);
ImageIO.write(outputImage, "WebP", baos);
} catch (final IOException e) {
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// create the output stream:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// TODO: check how to remove buffer file !!! here, it is not needed at all...
ImageIO.write( outputImage, "JPG", baos);
} catch (IOException e) {
e.printStackTrace();
return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain")
.build();
return Response.status(500).
entity("Internal Error: resize fail: " + e.getMessage()).
type("text/plain").
build();
}
final byte[] imageData = baos.toByteArray();
LOGGER.info("output length {}", imageData.length);
// Response.ok(new ByteArrayInputStream(imageData)).build();
final Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH,
imageData.length);
//out.type("image/jpeg");
out.type("image/webp");
//out.type("image/png");
// TODO: move this in a decorator !!!
final CacheControl cc = new CacheControl();
cc.setMaxAge(3600);
cc.setNoCache(false);
out.cacheControl(cc);
return out.build();
}
try {
return buildStream(filePathName, range, value.mimeType);
} catch (final Exception ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to build output stream", ex);
}
}
byte[] imageData = baos.toByteArray();
//Response.ok(new ByteArrayInputStream(imageData)).build();
Response.ResponseBuilder out = Response.ok(imageData)
.header(HttpHeaders.CONTENT_LENGTH, imageData.length);
out.type("image/jpeg");
// TODO: move this in a decorator !!!
CacheControl cc = new CacheControl();
cc.setMaxAge(3600);
cc.setNoCache(false);
out.cacheControl(cc);
return out.build();
}
return buildStream(filePathName, range, value.mimeType);
}
//@Secured
@GET
@Path("{id}/{name}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveDataFull(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id, @PathParam("name") String name) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
//System.out.println("===================================================");
System.out.println("== DATA retriveDataFull ? id=" + id + " user=" + (gc==null?"null":gc.user));
//System.out.println("===================================================");
Data value = getSmall(id);
if (value == null) {
Response.status(404).
entity("media NOT FOUND: " + id).
type("text/plain").
build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
}
@GET
@Path("{oid}/{name}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Operation(description = "Get back some data from the data environment (with a beautiful name (permit download with basic name)", tags = "SYSTEM")
public Response retrieveDataFull(
@Context final SecurityContext sc,
@QueryParam(HttpHeaders.AUTHORIZATION) final String token,
@HeaderParam("Range") final String range,
@PathParam("oid") final ObjectId oid,
@PathParam("name") final String name) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
// logger.info("===================================================");
LOGGER.info("== DATA retrieveDataFull ? id={} user={}", oid, (gc == null ? "null" : gc.userByToken));
// logger.info("===================================================");
final Data value = getSmall(oid);
if (value == null) {
return Response.status(404).entity("media NOT FOUND: " + oid).type("text/plain").build();
}
return buildStream(getFileData(oid), range,
value.mimeType == null ? "application/octet-stream" : value.mimeType);
}
/**
* Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541
*
* @param range range header
* @return Streaming output
* @throws Exception IOException if an error occurs in streaming.
*/
private Response buildStream(final String filename, final String range, String mimeType) throws Exception {
File file = new File(filename);
//System.out.println("request range : " + range);
// range not requested : Firefox does not send range headers
if (range == null) {
final StreamingOutput output = new StreamingOutput() {
@Override
public void write(OutputStream out) {
try (FileInputStream in = new FileInputStream(file)) {
byte[] buf = new byte[1024 * 1024];
int len;
while ((len = in.read(buf)) != -1) {
try {
out.write(buf, 0, len);
out.flush();
//System.out.println("---- wrote " + len + " bytes file ----");
} catch (IOException ex) {
System.out.println("remote close connection");
break;
}
}
} catch (IOException ex) {
throw new InternalServerErrorException(ex);
}
}
};
Response.ResponseBuilder out = Response.ok(output)
.header(HttpHeaders.CONTENT_LENGTH, file.length());
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
/** Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541
*
* @param range range header
* @return Streaming output
* @throws FileNotFoundException
* @throws Exception IOException if an error occurs in streaming. */
private Response buildStream(final String filename, final String range, final String mimeType)
throws FailException {
final File file = new File(filename);
// logger.info("request range : {}", range);
// range not requested : Firefox does not send range headers
if (range == null) {
final StreamingOutput output = new StreamingOutput() {
@Override
public void write(final OutputStream out) {
try (FileInputStream in = new FileInputStream(file)) {
final byte[] buf = new byte[1024 * 1024];
int len;
while ((len = in.read(buf)) != -1) {
try {
out.write(buf, 0, len);
out.flush();
// logger.info("---- wrote {} bytes file ----", len);
} catch (final IOException ex) {
LOGGER.info("remote close connection");
break;
}
}
} catch (final IOException ex) {
throw new InternalServerErrorException(ex);
}
}
};
final Response.ResponseBuilder out = Response.ok(output).header(HttpHeaders.CONTENT_LENGTH, file.length());
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
}
}
String[] ranges = range.split("=")[1].split("-");
final long from = Long.parseLong(ranges[0]);
final String[] ranges = range.split("=")[1].split("-");
final long from = Long.parseLong(ranges[0]);
//System.out.println("request range : " + ranges.length);
//Chunk media if the range upper bound is unspecified. Chrome, Opera sends "bytes=0-"
long to = CHUNK_SIZE + from;
if (ranges.length == 1) {
to = file.length() - 1;
} else {
if (to >= file.length()) {
to = (long) (file.length() - 1);
}
}
final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length());
//System.out.println("responseRange : " + responseRange);
final RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(from);
// logger.info("request range : {}", ranges.length);
// Chunk media if the range upper bound is unspecified. Chrome, Opera sends "bytes=0-"
long to = CHUNK_SIZE + from;
if (ranges.length == 1) {
to = file.length() - 1;
} else if (to >= file.length()) {
to = file.length() - 1;
}
final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length());
// LOGGER.info("responseRange: {}", responseRange);
try {
final RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(from);
final long len = to - from + 1;
final MediaStreamer streamer = new MediaStreamer(len, raf);
Response.ResponseBuilder out = Response.ok(streamer)
.status(Response.Status.PARTIAL_CONTENT)
.header("Accept-Ranges", "bytes")
.header("Content-Range", responseRange)
.header(HttpHeaders.CONTENT_LENGTH, streamer.getLenth())
.header(HttpHeaders.LAST_MODIFIED, new Date(file.lastModified()));
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
}
final long len = to - from + 1;
final MediaStreamer streamer = new MediaStreamer(len, raf);
final Response.ResponseBuilder out = Response.ok(streamer).status(Response.Status.PARTIAL_CONTENT)
.header("Accept-Ranges", "bytes").header("Content-Range", responseRange)
.header(HttpHeaders.CONTENT_LENGTH, streamer.getLenth())
.header(HttpHeaders.LAST_MODIFIED, new Date(file.lastModified()));
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
} catch (final FileNotFoundException ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to find the required file.", ex);
} catch (final IOException ex) {
throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Fail to access to the required file.", ex);
}
}
public void undelete(final Long id) throws Exception {
DataAccess.unsetDelete(Data.class, id);
public static void undelete(Long id) throws Exception {
SqlWrapper.unsetDelete(Data.class, id);
}
}

View File

@ -3,113 +3,103 @@ package org.kar.archidata.api;
import java.io.File;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.*;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import org.kar.archidata.annotation.security.PermitAll;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.NotSupportedException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.CacheControl;
import jakarta.ws.rs.core.PathSegment;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.ResponseBuilder;
public class FrontGeneric {
private static final Logger LOGGER = LoggerFactory.getLogger(FrontGeneric.class);
protected String baseFrontFolder = "/data/front";
private String getExtension(final String filename) {
if (filename.contains(".")) {
return filename.substring(filename.lastIndexOf(".") + 1);
}
return "";
private String getExtension(String filename) {
if (filename.contains(".")) {
return filename.substring(filename.lastIndexOf(".") + 1);
}
return "";
}
private Response retrive(String fileName) throws Exception {
String filePathName = baseFrontFolder + File.separator + fileName;
String extention = getExtension(filePathName);
String mineType = null;
System.out.println("try retrive : '" + filePathName + "' '" + extention + "'");
if (extention.length() !=0 && extention.length() <= 5) {
if (extention.equalsIgnoreCase("jpg") || extention.equalsIgnoreCase("jpeg")) {
mineType = "image/jpeg";
} else if (extention.equalsIgnoreCase("gif")) {
mineType = "image/gif";
} else if (extention.equalsIgnoreCase("png")) {
mineType = "image/png";
} else if (extention.equalsIgnoreCase("svg")) {
mineType = "image/svg+xml";
} else if (extention.equalsIgnoreCase("webp")) {
mineType = "image/webp";
} else if (extention.equalsIgnoreCase("js")) {
mineType = "application/javascript";
} else if (extention.equalsIgnoreCase("json")) {
mineType = "application/json";
} else if (extention.equalsIgnoreCase("ico")) {
mineType = "image/x-icon";
} else if (extention.equalsIgnoreCase("html")) {
mineType = "text/html";
} else if (extention.equalsIgnoreCase("css")) {
mineType = "text/css";
} else {
return Response.status(403).
entity("Not supported model: '" + fileName + "'").
type("text/plain").
build();
}
} else {
mineType = "text/html";
filePathName = baseFrontFolder + File.separator + "index.html";
}
System.out.println(" ==> '" + filePathName + "'");
// reads input image
File download = new File(filePathName);
if (!download.exists()) {
return Response.status(404).
entity("Not Found: '" + fileName + "' extension='" + extention + "'").
type("text/plain").
build();
}
ResponseBuilder response = Response.ok((Object)download);
// use this if I want to download the file:
//response.header("Content-Disposition", "attachment; filename=" + fileName);
CacheControl cc = new CacheControl();
cc.setMaxAge(60);
cc.setNoCache(false);
response.cacheControl(cc);
response.type(mineType);
return response.build();
}
private Response retrive(final String fileName) throws Exception {
String filePathName = this.baseFrontFolder + File.separator + fileName;
final String extention = getExtension(filePathName);
String mineType = null;
LOGGER.debug("try retrive : '{}' '{}'", filePathName, extention);
if (extention.length() != 0 && extention.length() <= 5) {
if (extention.equalsIgnoreCase("jpg") || extention.equalsIgnoreCase("jpeg")) {
mineType = "image/jpeg";
} else if (extention.equalsIgnoreCase("gif")) {
mineType = "image/gif";
} else if (extention.equalsIgnoreCase("png")) {
mineType = "image/png";
} else if (extention.equalsIgnoreCase("svg")) {
mineType = "image/svg+xml";
} else if (extention.equalsIgnoreCase("webp")) {
mineType = "image/webp";
} else if (extention.equalsIgnoreCase("js")) {
mineType = "application/javascript";
} else if (extention.equalsIgnoreCase("json")) {
mineType = "application/json";
} else if (extention.equalsIgnoreCase("ico")) {
mineType = "image/x-icon";
} else if (extention.equalsIgnoreCase("html")) {
mineType = "text/html";
} else if (extention.equalsIgnoreCase("css")) {
mineType = "text/css";
} else if (extention.equalsIgnoreCase("mka")) {
mineType = "audio/x-matroska";
} else if (extention.equalsIgnoreCase("mkv")) {
mineType = "video/x-matroska";
} else if (extention.equalsIgnoreCase("webm")) {
mineType = "video/webm";
} else {
throw new NotSupportedException("Not supported model: '" + fileName + "'");
}
} else {
mineType = "text/html";
filePathName = this.baseFrontFolder + File.separator + "index.html";
}
LOGGER.debug(" ==> '[}'", filePathName);
// reads input image
final File download = new File(filePathName);
if (!download.exists()) {
throw new NotFoundException("Not Found: '" + fileName + "' extension='" + extention + "'");
}
final ResponseBuilder response = Response.ok(download);
// use this if I want to download the file:
// response.header("Content-Disposition", "attachment; filename=" + fileName);
final CacheControl cc = new CacheControl();
cc.setMaxAge(60);
cc.setNoCache(false);
response.cacheControl(cc);
response.type(mineType);
return response.build();
}
@GET
@PermitAll()
@Operation(description = "Retrieve native element (index)", tags = "SYSTEM")
// @Produces(MediaType.APPLICATION_OCTET_STREAM)
// @CacheMaxAge(time = 1, unit = TimeUnit.DAYS)
public Response retrive0() throws Exception {
return retrive("index.html");
}
@GET
@Path("{any: .*}")
@PermitAll()
@Operation(description = "Get specific file from the front environment", tags = "SYSTEM")
// @Produces(MediaType.APPLICATION_OCTET_STREAM)
// @CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retrive1(@PathParam("any") final List<PathSegment> segments) throws Exception {
String filename = "";
for (final PathSegment elem : segments) {
if (!filename.isEmpty()) {
filename += File.separator;
}
filename += elem.getPath();
}
return retrive(filename);
}
@GET
@PermitAll()
//@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 1, unit = TimeUnit.DAYS)
public Response retrive0() throws Exception {
return retrive("index.html");
}
@GET
@Path("{any: .*}")
@PermitAll()
//@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retrive1(@PathParam("any") List<PathSegment> segments) throws Exception {
String filename = "";
for (PathSegment elem: segments) {
if (!filename.isEmpty()) {
filename += File.separator;
}
filename += elem.getPath();
}
return retrive(filename);
}
}

View File

@ -1,61 +1,56 @@
package org.kar.archidata.api;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.StreamingOutput;
public class MediaStreamer implements StreamingOutput {
private static final Logger LOGGER = LoggerFactory.getLogger(MediaStreamer.class);
private final int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
final byte[] buf = new byte[this.CHUNK_SIZE];
private long length;
private final RandomAccessFile raf;
private final int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
final byte[] buf = new byte[CHUNK_SIZE];
private long length;
private RandomAccessFile raf;
public MediaStreamer(final long length, final RandomAccessFile raf) throws IOException {
// logger.info("request stream of {} data", length / 1024);
if (length < 0) {
throw new IOException("Wrong size of the file to stream: " + length);
}
this.length = length;
this.raf = raf;
}
public MediaStreamer(long length, RandomAccessFile raf) throws IOException {
//System.out.println("request stream of " + length / 1024 + " data");
if (length<0) {
throw new IOException("Wrong size of the file to stream: " + length);
}
this.length = length;
this.raf = raf;
}
@Override
public void write(final OutputStream outputStream) {
try {
while (this.length != 0) {
final int read = this.raf.read(this.buf, 0,
this.buf.length > this.length ? (int) this.length : this.buf.length);
try {
outputStream.write(this.buf, 0, read);
} catch (final IOException ex) {
LOGGER.info("remote close connection");
break;
}
this.length -= read;
}
} catch (final IOException ex) {
throw new InternalServerErrorException(ex);
} catch (final WebApplicationException ex) {
throw new InternalServerErrorException(ex);
} finally {
try {
this.raf.close();
} catch (final IOException ex) {
ex.printStackTrace();
throw new InternalServerErrorException(ex);
}
}
}
@Override
public void write(OutputStream outputStream) {
try {
while (length != 0) {
int read = raf.read(buf, 0, buf.length > length ? (int) length : buf.length);
try {
outputStream.write(buf, 0, read);
} catch (IOException ex) {
System.out.println("remote close connection");
break;
}
length -= read;
}
} catch (IOException ex) {
throw new InternalServerErrorException(ex);
} catch (WebApplicationException ex) {
throw new InternalServerErrorException(ex);
} finally {
try {
raf.close();
} catch (IOException ex) {
ex.printStackTrace();
throw new InternalServerErrorException(ex);
}
}
}
public long getLenth() {
return length;
}
public long getLenth() {
return this.length;
}
}

View File

@ -1,43 +0,0 @@
package org.kar.archidata.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@Path("/proxy")
//@Produces(MediaType.APPLICATION_JSON)
public class ProxyResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ProxyResource.class);
@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getImageFromUrl(@QueryParam("url") final String url) {
if (url == null || url.isEmpty()) {
return Response.status(Status.BAD_REQUEST).entity("URL manquante").build();
}
final Client client = ClientBuilder.newClient();
try {
final WebTarget target = client.target(url);
final Response response = target.request().get();
if (response.getStatus() != 200) {
return Response.status(Status.BAD_GATEWAY).entity("Can not get the image : " + response.getStatus())
.build();
}
return Response.ok(response.readEntity(byte[].class)).header("Access-Control-Allow-Origin", "*")
.header("Content-Type", response.getHeaderString("Content-Type")).build();
} catch (final Exception e) {
return Response.status(Status.INTERNAL_SERVER_ERROR).entity("SERVER internal error : " + e.getMessage())
.build();
}
}
}

View File

@ -1,34 +0,0 @@
package org.kar.archidata.api;
import io.swagger.v3.jaxrs2.integration.resources.BaseOpenApiResource;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.ServletConfig;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
@Path("/openapi")
public class openApiResource extends BaseOpenApiResource {
@Context
ServletConfig config;
@Context
Application app;
@GET
@Path("swagger.json")
@Produces({ MediaType.APPLICATION_JSON })
@PermitAll
@Operation(hidden = true, description = "Get the OPEN-API description", tags = "SYSTEM")
public Response getDescription(@Context final HttpHeaders headers, @Context final UriInfo uriInfo)
throws Exception {
return getOpenApi(headers, this.config, this.app, uriInfo, "json");
}
}

View File

@ -1,29 +0,0 @@
package org.kar.archidata.backup;
import java.util.ArrayList;
import java.util.List;
public class BackupEngine {
public enum StoreMode {
JSON, SQL
}
private final String pathStore;
private final StoreMode mode;
private final List<Class<?>> classes = new ArrayList<>();
public BackupEngine(final String pathToStoreDB, final StoreMode mode) {
this.pathStore = pathToStoreDB;
this.mode = mode;
}
public void addClass(final Class<?> clazz) {
this.classes.add(clazz);
}
public void store() {
// TODO ...
}
}

View File

@ -1,28 +1,26 @@
package org.kar.archidata.catcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class ExceptionCatcher implements ExceptionMapper<Exception> {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatcher.class);
public class ExceptionCatcher
implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception exception) {
System.out.println("Catch exception (not managed...):");
RestErrorResponse ret = build(exception);
System.out.println("Error UUID=" + ret.uuid);
exception.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build();
}
@Override
public Response toResponse(final Exception exception) {
LOGGER.warn("Catch exception (not managed...):");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
exception.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ret).type(MediaType.APPLICATION_JSON)
.build();
}
private RestErrorResponse build(final Exception exception) {
return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR,
"Catch Unknown Exception: " + exception.getClass().getCanonicalName(), exception.getMessage());
}
private RestErrorResponse build(Exception exception) {
return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Catch Unknown Exception", exception.getMessage());
}
}

View File

@ -1,29 +1,28 @@
package org.kar.archidata.catcher;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import org.kar.archidata.exception.FailException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class FailExceptionCatcher implements ExceptionMapper<FailException> {
private static final Logger LOGGER = LoggerFactory.getLogger(FailExceptionCatcher.class);
public class FailExceptionCatcher
implements ExceptionMapper<FailException> {
@Override
public Response toResponse(FailException exception) {
RestErrorResponse ret = build(exception);
System.out.println("Error UUID=" + ret.uuid);
// Not display backtrace ==> this may be a normal case ...
//exception.printStackTrace();
return Response.status(exception.status)
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build();
}
@Override
public Response toResponse(final FailException exception) {
LOGGER.warn("Catch FailException: {}", exception.getLocalizedMessage());
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
if (exception.exception != null) {
exception.exception.printStackTrace();
}
return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(final FailException exception) {
return new RestErrorResponse(exception.status, "Request Fail", exception.getMessage());
}
private RestErrorResponse build(FailException exception) {
return new RestErrorResponse(exception.status, "Request Fail", exception.getMessage());
}
}

View File

@ -1,24 +0,0 @@
package org.kar.archidata.catcher;
import org.glassfish.jersey.server.ResourceConfig;
public class GenericCatcher {
/**
* Add All the the generic catcher to standardize returns.
* @param rc Resource exception model.
*/
public static void addAll(final ResourceConfig rc) {
// Generic Json parsing error
rc.register(JacksonExceptionCatcher.class);
// Catch jakarta generic errors
rc.register(WebApplicationExceptionCatcher.class);
// Archidata exceptions
rc.register(InputExceptionCatcher.class);
rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class);
// generic Exception catcher
rc.register(ExceptionCatcher.class);
}
}

View File

@ -1,45 +1,27 @@
package org.kar.archidata.catcher;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import org.kar.archidata.exception.InputException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
/**
* This class catches InputException and maps it to a HTTP response.
*/
public class InputExceptionCatcher implements ExceptionMapper<InputException> {
private static final Logger LOGGER = LoggerFactory.getLogger(InputExceptionCatcher.class);
public class InputExceptionCatcher
implements ExceptionMapper<InputException> {
@Override
public Response toResponse(InputException exception) {
RestErrorResponse ret = build(exception);
System.out.println("Error UUID=" + ret.uuid);
exception.printStackTrace();
return Response.status(exception.status)
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build();
}
/**
* This method is called when an InputException is thrown.
* It logs the exception and builds a response with the error details.
*
* @param exception the InputException that was thrown
* @return a Response object containing the error details
*/
@Override
public Response toResponse(final InputException exception) {
LOGGER.warn("Catch InputException:");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={} ==> '{}'=>'{}'", ret.oid, exception.missingVariable,
exception.getLocalizedMessage());
// exception.printStackTrace();
return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
/**
* This method builds a RestErrorResponse object from the InputException.
*
* @param exception the InputException that was thrown
* @return a RestErrorResponse object containing the error details
*/
private RestErrorResponse build(final InputException exception) {
return new RestErrorResponse(exception.status, "Error on input='" + exception.missingVariable + "'",
exception.getMessage());
}
private RestErrorResponse build(InputException exception) {
return new RestErrorResponse(exception.status, "Error on input='" + exception.missingVariable + "'" , exception.getMessage());
}
}

View File

@ -1,43 +0,0 @@
package org.kar.archidata.catcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JacksonException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class JacksonExceptionCatcher implements ExceptionMapper<JacksonException> {
private static final Logger LOGGER = LoggerFactory.getLogger(JacksonExceptionCatcher.class);
/**
* This method is called when a JacksonException is thrown.
* It logs the exception, builds a response with the error details, and returns it.
*
* @param exception the JacksonException that was thrown
* @return a Response object containing the error details
*/
@Override
public Response toResponse(final JacksonException exception) {
LOGGER.warn("Catch exception Input data parsing:");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
exception.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ret).type(MediaType.APPLICATION_JSON)
.build();
}
/**
* Builds a RestErrorResponse object from the given exception.
*
* @param exception the Exception that was thrown
* @return a RestErrorResponse object containing the error details
*/
private RestErrorResponse build(final Exception exception) {
return new RestErrorResponse(Response.Status.INTERNAL_SERVER_ERROR, "Catch JSON Exception",
exception.getMessage());
}
}

View File

@ -1,55 +1,35 @@
package org.kar.archidata.catcher;
import java.time.Instant;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.NoWriteSpecificMode;
import javax.ws.rs.core.Response;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.core.Response;
@NoWriteSpecificMode
public class RestErrorResponse {
public ObjectId oid = new ObjectId();
@NotNull
@Column(length = 0)
public String name; // Mandatory for TS generic error
@NotNull
@Column(length = 0)
public String message; // Mandatory for TS generic error
@NotNull
@Column(length = 0)
public String time;
@NotNull
public UUID uuid = UUID.randomUUID();
public String time;
public String error;
public String message;
final public int status;
@NotNull
@Column(length = 0)
final public String statusMessage;
public RestErrorResponse(final Response.Status status, final String time, final String error,
final String message) {
public RestErrorResponse(Response.Status status, String time, String error, String message) {
this.time = time;
this.name = error;
this.error = error;
this.message = message;
this.status = status.getStatusCode();
this.statusMessage = status.getReasonPhrase();
}
public RestErrorResponse(final Response.Status status, final String error, final String message) {
public RestErrorResponse(Response.Status status, String error, String message) {
this.time = Instant.now().toString();
this.name = error;
this.error = error;
this.message = message;
this.status = status.getStatusCode();
this.statusMessage = status.getReasonPhrase();
}
public RestErrorResponse(final Response.Status status) {
this.name = "generic";
this.message = "";
public RestErrorResponse(Response.Status status) {
this.time = Instant.now().toString();
this.status = status.getStatusCode();
this.statusMessage = status.getReasonPhrase();
}
}

View File

@ -1,27 +1,28 @@
package org.kar.archidata.catcher;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import org.kar.archidata.exception.InputException;
import org.kar.archidata.exception.SystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class SystemExceptionCatcher implements ExceptionMapper<SystemException> {
private static final Logger LOGGER = LoggerFactory.getLogger(SystemExceptionCatcher.class);
public class SystemExceptionCatcher
implements ExceptionMapper<SystemException> {
@Override
public Response toResponse(SystemException exception) {
RestErrorResponse ret = build(exception);
System.out.println("Error UUID=" + ret.uuid);
exception.printStackTrace();
return Response.status(exception.status)
.entity(ret)
.type(MediaType.APPLICATION_JSON)
.build();
}
@Override
public Response toResponse(final SystemException exception) {
LOGGER.warn("Catch SystemException:");
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
exception.printStackTrace();
return Response.status(exception.status).entity(ret).type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(final SystemException exception) {
return new RestErrorResponse(exception.status, "System error", exception.getMessage());
}
private RestErrorResponse build(SystemException exception) {
return new RestErrorResponse(exception.status, "System error", exception.getMessage());
}
}

View File

@ -1,28 +0,0 @@
package org.kar.archidata.catcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
public class WebApplicationExceptionCatcher implements ExceptionMapper<WebApplicationException> {
private static final Logger LOGGER = LoggerFactory.getLogger(WebApplicationExceptionCatcher.class);
@Override
public Response toResponse(final WebApplicationException exception) {
final RestErrorResponse ret = build(exception);
LOGGER.error("Error OID={}", ret.oid);
return Response.status(exception.getResponse().getStatusInfo().toEnum()).entity(ret)
.type(MediaType.APPLICATION_JSON).build();
}
private RestErrorResponse build(final WebApplicationException exception) {
exception.printStackTrace();
return new RestErrorResponse(exception.getResponse().getStatusInfo().toEnum(), "Catch system exception",
exception.getMessage());
}
}

View File

@ -1,898 +0,0 @@
package org.kar.archidata.checker;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.checker.CheckForeignKey;
import org.kar.archidata.annotation.checker.Checker;
import org.kar.archidata.annotation.checker.CollectionItemNotNull;
import org.kar.archidata.annotation.checker.CollectionItemUnique;
import org.kar.archidata.annotation.checker.CollectionNotEmpty;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.QueryOptions;
import org.kar.archidata.dataAccess.options.CheckFunctionInterface;
import org.kar.archidata.dataAccess.options.CheckFunctionVoid;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.ConditionChecker;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.exception.InputException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.persistence.ManyToOne;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Size;
public class CheckJPA<T> implements CheckFunctionInterface {
private static final Logger LOGGER = LoggerFactory.getLogger(CheckJPA.class);
private final Class<?> clazz;
/** By default some element are not read like createAt and UpdatedAt. This option permit to read it. */
public interface CheckInterface<K> {
/** This function implementation is design to check if the updated class is valid of not for insertion
* @param ioDb Access on the Data-Base
* @param baseName Base of the name input that is displayed in exception generated.
* @param data The object that might be injected.
* @param modifiedValue List of fields that modification is requested.
* @param options Some query option that the checker can need to generate basic check.
* @throws Exception Exception is generate if the data are incorrect. */
void check(
final DBAccess ioDb,
final String baseName,
final K data,
List<String> modifiedValue,
final QueryOptions options) throws Exception;
}
protected Map<String, List<CheckInterface<T>>> checking = null;
protected void add(final String field, final CheckInterface<T> checkFunction) throws DataAccessException {
if (!AnnotationTools.hasFieldsName(this.clazz, field)) {
LOGGER.error("Try to add a JPA Filter on an inexistant Field: '{}' not in {}", field,
AnnotationTools.getAllFieldsNames(this.clazz));
throw new DataAccessException("Try to add a JPA Filter on an inexistant Field: '" + field + "' not in "
+ AnnotationTools.getAllFieldsNames(this.clazz));
}
List<CheckInterface<T>> actions = this.checking.get(field);
if (actions == null) {
actions = new ArrayList<>();
this.checking.put(field, actions);
}
actions.add(checkFunction);
}
public CheckJPA(final Class<T> clazz) {
this.clazz = clazz;
}
public void initialize() throws Exception {
if (this.checking != null) {
return;
}
try {
this.checking = new HashMap<>();
// create Table:
final List<String> primaryKeys = new ArrayList<>();
for (final Field field : this.clazz.getFields()) {
final String fieldName = field.getName(); // AnnotationTools.getFieldName(field);
if (AnnotationTools.isPrimaryKey(field)) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
throw new InputException(baseName + fieldName,
"This is a '@Id' (primaryKey) ==> can not be change");
});
}
if (AnnotationTools.getConstraintsNotNull(field)) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
if (field.get(data) == null) {
throw new InputException(baseName + fieldName, "Can not be null");
}
});
}
if (AnnotationTools.isCreatedAtField(field) || AnnotationTools.isUpdateAtField(field)) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
throw new InputException(baseName + fieldName, "It is forbidden to change this field");
});
}
final Class<?> type = field.getType();
if (type == Long.class || type == long.class) {
final DecimalMax maxValueDecimal = AnnotationTools.getConstraintsDecimalMax(field);
if (maxValueDecimal != null) {
final long maxValue = Long.parseLong(maxValueDecimal.value());
final boolean inclusive = maxValueDecimal.inclusive();
final String exceptionComment = "Value too height max=" + maxValue
+ (inclusive ? " (inclusive)" : " (exclusive)");
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Long elemTyped = (Long) elem;
if (inclusive) {
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
} else if (elemTyped >= maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final DecimalMin minValueDecimal = AnnotationTools.getConstraintsDecimalMin(field);
if (minValueDecimal != null) {
final long minValue = Long.parseLong(minValueDecimal.value());
final boolean inclusive = minValueDecimal.inclusive();
final String exceptionComment = "Value too low min=" + minValue
+ (inclusive ? " (inclusive)" : " (exclusive)");
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Long elemTyped = (Long) elem;
if (inclusive) {
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
} else if (elemTyped <= minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final Max maxValue = AnnotationTools.getConstraintsMax(field);
if (maxValue != null) {
final Long maxValueTmp = maxValue.value();
final String exceptionComment = "Value too height max=" + maxValueTmp + " (inclusive)";
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Long elemTyped = (Long) elem;
if (elemTyped > maxValueTmp) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final Min minValue = AnnotationTools.getConstraintsMin(field);
if (minValue != null) {
final Long minValueTmp = minValue.value();
final String exceptionComment = "Value too low min=" + minValueTmp + " (inclusive)";
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Long elemTyped = (Long) elem;
if (elemTyped < minValueTmp) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
} else if (type == Integer.class || type == int.class) {
final DecimalMax maxValueDecimal = AnnotationTools.getConstraintsDecimalMax(field);
if (maxValueDecimal != null) {
final int maxValue = Integer.parseInt(maxValueDecimal.value());
final boolean inclusive = maxValueDecimal.inclusive();
final String exceptionComment = "Value too height max=" + maxValue
+ (inclusive ? " (inclusive)" : " (exclusive)");
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Integer elemTyped = (Integer) elem;
if (inclusive) {
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
} else if (elemTyped >= maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final DecimalMin minValueDecimal = AnnotationTools.getConstraintsDecimalMin(field);
if (minValueDecimal != null) {
final int minValue = Integer.parseInt(minValueDecimal.value());
final boolean inclusive = minValueDecimal.inclusive();
final String exceptionComment = "Value too low min=" + minValue
+ (inclusive ? " (inclusive)" : " (exclusive)");
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Integer elemTyped = (Integer) elem;
if (inclusive) {
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
} else if (elemTyped <= minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final Max maxValueRoot = AnnotationTools.getConstraintsMax(field);
if (maxValueRoot != null) {
final int maxValue = (int) maxValueRoot.value();
final String exceptionComment = "Value too height max=" + maxValue + " (inclusive)";
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Integer elemTyped = (Integer) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final Min minValueRoot = AnnotationTools.getConstraintsMin(field);
if (minValueRoot != null) {
final int minValue = (int) minValueRoot.value();
final String exceptionComment = "Value too low min=" + minValue + " (inclusive)";
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Integer elemTyped = (Integer) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
} else if (type == Boolean.class || type == boolean.class) {
} else if (type == Float.class || type == float.class) {
final DecimalMax maxValueDecimal = AnnotationTools.getConstraintsDecimalMax(field);
if (maxValueDecimal != null) {
final float maxValue = Float.parseFloat(maxValueDecimal.value());
final boolean inclusive = maxValueDecimal.inclusive();
final String exceptionComment = "Value too height max=" + maxValue
+ (inclusive ? " (inclusive)" : " (exclusive)");
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Float elemTyped = (Float) elem;
if (inclusive) {
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
} else if (elemTyped >= maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final DecimalMin minValueDecimal = AnnotationTools.getConstraintsDecimalMin(field);
if (minValueDecimal != null) {
final float minValue = Float.parseFloat(minValueDecimal.value());
final boolean inclusive = minValueDecimal.inclusive();
final String exceptionComment = "Value too low min=" + minValue
+ (inclusive ? " (inclusive)" : " (exclusive)");
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Float elemTyped = (Float) elem;
if (inclusive) {
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
} else if (elemTyped <= minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final Max maxValueRoot = AnnotationTools.getConstraintsMax(field);
if (maxValueRoot != null) {
final float maxValue = maxValueRoot.value();
final String exceptionComment = "Value too height max=" + maxValue + " (inclusive)";
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Float elemTyped = (Float) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final Min minValueRoot = AnnotationTools.getConstraintsMin(field);
if (minValueRoot != null) {
final float minValue = minValueRoot.value();
final String exceptionComment = "Value too low min=" + minValue + " (inclusive)";
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Float elemTyped = (Float) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
} else if (type == Double.class || type == double.class) {
final DecimalMax maxValueDecimal = AnnotationTools.getConstraintsDecimalMax(field);
if (maxValueDecimal != null) {
final double maxValue = Float.parseFloat(maxValueDecimal.value());
final boolean inclusive = maxValueDecimal.inclusive();
final String exceptionComment = "Value too height max=" + maxValue
+ (inclusive ? " (inclusive)" : " (exclusive)");
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Double elemTyped = (Double) elem;
if (inclusive) {
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
} else if (elemTyped >= maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final DecimalMin minValueDecimal = AnnotationTools.getConstraintsDecimalMin(field);
if (minValueDecimal != null) {
final double minValue = Float.parseFloat(minValueDecimal.value());
final boolean inclusive = minValueDecimal.inclusive();
final String exceptionComment = "Value too low min=" + minValue
+ (inclusive ? " (inclusive)" : " (exclusive)");
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Double elemTyped = (Double) elem;
if (inclusive) {
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName,
"Value too Low min: " + minValue);
}
} else if (elemTyped <= minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final Max maxValueRoot = AnnotationTools.getConstraintsMax(field);
if (maxValueRoot != null) {
final double maxValue = maxValueRoot.value();
final String exceptionComment = "Value too height max=" + maxValue + " (inclusive)";
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Double elemTyped = (Double) elem;
if (elemTyped > maxValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
final Min minValueRoot = AnnotationTools.getConstraintsMin(field);
if (minValueRoot != null) {
final double minValue = minValueRoot.value();
final String exceptionComment = "Value too low min=" + minValue + " (inclusive)";
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final Double elemTyped = (Double) elem;
if (elemTyped < minValue) {
throw new InputException(baseName + fieldName, exceptionComment);
}
});
}
} else if (type == Date.class || type == Timestamp.class) {
} else if (type == LocalDate.class) {
} else if (type == LocalTime.class) {
} else if (type == String.class) {
final Size limitSize = AnnotationTools.getConstraintsSize(field);
if (limitSize != null) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (elemTyped.length() > limitSize.max()) {
throw new InputException(baseName + fieldName,
"Too long size (constraints) must be <= " + limitSize.max());
}
if (elemTyped.length() < limitSize.min()) {
throw new InputException(baseName + fieldName,
"Too small size (constraints) must be >= " + limitSize.min());
}
});
}
final jakarta.validation.constraints.Pattern patternString = AnnotationTools
.getConstraintsPattern(field);
if (patternString != null && patternString.regexp() != null) {
final Pattern pattern = Pattern.compile(patternString.regexp());
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (!pattern.matcher(elemTyped).find()) {
throw new InputException(baseName + fieldName,
"does not match the required pattern (constraints) must be '" + pattern
+ "'");
}
});
}
if (AnnotationTools.getConstraintsEmail(field) != null) {
final String emailPattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
final Pattern pattern = Pattern.compile(emailPattern);
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final String elemTyped = (String) elem;
if (!pattern.matcher(elemTyped).find()) {
throw new InputException(baseName + fieldName,
"does not match the required pattern[email] (constraints) must be '"
+ emailPattern + "'");
}
});
}
} else if (type.isEnum()) {
// nothing to do.
}
final Checker[] checkers = AnnotationTools.getConstraintsCheckers(field);
if (checkers != null) {
for (final Checker checker : checkers) {
if (checker == null || checker.value() == CheckFunctionVoid.class) {
continue;
}
final CheckFunctionInterface checkerInstance = checker.value().getDeclaredConstructor()
.newInstance();
if (Collection.class.isAssignableFrom(field.getType())) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
// get the field of the specific element
final Object tmpData = field.get(data);
// It is not the objective of this element to check if it is authorize to set NULL
if (tmpData == null) {
return;
}
final Collection<?> tmpCollection = (Collection<?>) tmpData;
final Object[] elements = tmpCollection.toArray();
for (int iii = 0; iii < elements.length; iii++) {
if (elements[iii] != null) {
checkerInstance.check(ioDb, baseName + fieldName + '[' + iii + "].",
elements[iii], null, options);
}
}
});
} else {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
// get the field of the specific element
final Object tmpData = field.get(data);
// It is not the objective of this element to check if it is authorize to set NULL
if (tmpData == null) {
return;
}
checkerInstance.check(ioDb, baseName + fieldName + '.', tmpData, null, options);
});
}
}
}
final CheckForeignKey foreighKey = AnnotationTools.get(field, CheckForeignKey.class);
if (foreighKey != null) {
if (Collection.class.isAssignableFrom(field.getType())) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
// get the field of the specific element
final Object tmpData = field.get(data);
// It is not the objective of this element to check if it is authorize to set NULL
if (tmpData == null) {
return;
}
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
final Condition conditionCheck = condCheckers.isEmpty() ? null
: condCheckers.get(0).toCondition();
final Collection<?> tmpCollection = (Collection<?>) tmpData;
final Object[] elements = tmpCollection.toArray();
for (int iii = 0; iii < elements.length; iii++) {
if (elements[iii] == null) {
continue;
}
final Long count = ioDb.count(foreighKey.target(), elements[iii],
conditionCheck);
if (count != 1) {
throw new InputException(baseName + fieldName + '[' + iii + ']',
"Foreign-key does not exist in the DB:" + elements[iii]);
}
}
});
} else {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object tmpData = field.get(data);
if (tmpData == null) {
return;
}
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
final Condition conditionCheck = condCheckers.isEmpty() ? null
: condCheckers.get(0).toCondition();
final Long count = ioDb.count(foreighKey.target(), tmpData, conditionCheck);
if (count != 1) {
throw new InputException(baseName + fieldName,
"Foreign-key does not exist in the DB:" + tmpData);
}
});
}
}
// check if we really want to keep it ...
final ManyToOne annotationManyToOne = AnnotationTools.getManyToOne(field);
if (annotationManyToOne != null && annotationManyToOne.targetEntity() != null) {
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object elem = field.get(data);
if (elem == null) {
return;
}
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
final Condition conditionCheck = condCheckers.isEmpty() ? null
: condCheckers.get(0).toCondition();
final long count = ioDb.count(annotationManyToOne.targetEntity(), elem, conditionCheck);
if (count == 0) {
throw new InputException(baseName + fieldName,
"Foreign element does not exist in the DB:" + elem);
}
});
}
final CollectionItemUnique collectionUnique = AnnotationTools.getCollectionItemUnique(field);
if (collectionUnique != null) {
if (!Collection.class.isAssignableFrom(field.getType())) {
throw new DataAccessException(
"Request @CollectionItemUnique on a non collection field: '" + fieldName + "'");
}
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object tmpData = field.get(data);
if (tmpData == null) {
return;
}
final Collection<?> tmpCollection = (Collection<?>) tmpData;
final Set<Object> uniqueValues = new HashSet<>(tmpCollection);
if (uniqueValues.size() != tmpCollection.size()) {
throw new InputException(baseName + fieldName,
"Cannot insert multiple times the same elements");
}
});
}
final CollectionItemNotNull collectionNotNull = AnnotationTools.getCollectionItemNotNull(field);
if (collectionNotNull != null) {
if (!Collection.class.isAssignableFrom(field.getType())) {
throw new DataAccessException(
"Request @CollectionItemNotNull on a non collection field: '" + fieldName + "'");
}
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object tmpData = field.get(data);
if (tmpData == null) {
return;
}
final Collection<?> tmpCollection = (Collection<?>) tmpData;
final Object[] elements = tmpCollection.toArray();
for (int iii = 0; iii < elements.length; iii++) {
if (elements[iii] == null) {
throw new InputException(baseName + fieldName + '[' + iii + ']',
"Collection can not contain NULL item");
}
}
});
}
final CollectionNotEmpty collectionNotEmpty = AnnotationTools.getCollectionNotEmpty(field);
if (collectionNotEmpty != null) {
if (!Collection.class.isAssignableFrom(field.getType())) {
throw new DataAccessException(
"Request @collectionNotEmpty on a non collection field: '" + fieldName + "'");
}
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final Object tmpData = field.get(data);
if (tmpData == null) {
return;
}
final Collection<?> tmpCollection = (Collection<?>) tmpData;
if (tmpCollection.isEmpty()) {
throw new InputException(baseName + fieldName, "Collection can not be empty");
}
});
}
// keep this is last ==> take more time...
if (AnnotationTools.isUnique(field)) {
// Create the request ...
add(fieldName,
(
final DBAccess ioDb,
final String baseName,
final T data,
final List<String> modifiedValue,
final QueryOptions options) -> {
final List<ConditionChecker> condCheckers = options.get(ConditionChecker.class);
Object other = null;
if (condCheckers.isEmpty()) {
other = ioDb.getWhere(this.clazz,
new Condition(new QueryCondition(fieldName, "==", field.get(data))));
} else {
other = ioDb.getWhere(this.clazz,
new Condition(new QueryCondition(fieldName, "==", field.get(data))),
condCheckers.get(0).toCondition());
}
if (other != null) {
throw new InputException(baseName + fieldName,
"The field is already exist in the DB");
}
});
}
}
} catch (final Exception ex) {
this.checking = null;
throw ex;
}
}
public void check(final Object data) throws Exception {
check(null, "", data, null, null);
}
public void check(final String baseName, final Object data) throws Exception {
check(null, baseName, data, null, null);
}
public void check(final DBAccess ioDb, final String baseName, final Object data) throws Exception {
check(ioDb, baseName, data, null, null);
}
public void check(final DBAccess ioDb, final String baseName, final Object data, final List<String> modifiedValue)
throws Exception {
check(ioDb, baseName, data, modifiedValue, null);
}
@Override
public void check(
final DBAccess ioDb,
final String baseName,
final Object data,
List<String> modifiedValue,
final QueryOptions options) throws Exception {
if (this.checking == null) {
initialize();
}
if (modifiedValue == null) {
modifiedValue = AnnotationTools.getAllFieldsNames(this.clazz);
}
if (!(this.clazz.isAssignableFrom(data.getClass()))) {
throw new DataAccessException("Incompatatyble type of Object" + data.getClass().getCanonicalName());
}
@SuppressWarnings("unchecked")
final T dataCasted = (T) data;
for (final String filter : modifiedValue) {
final List<CheckInterface<T>> actions = this.checking.get(filter);
if (actions == null) {
continue;
}
for (final CheckInterface<T> action : actions) {
action.check(ioDb, baseName, dataCasted, modifiedValue, options);
}
}
checkTyped(dataCasted, modifiedValue, options);
}
public void checkTyped(final T data, final List<String> modifiedValue, final QueryOptions options)
throws Exception {
// nothing to do ...
}
}

View File

@ -1,14 +0,0 @@
package org.kar.archidata.converter.jackson;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class JacksonModules {
public static SimpleModule getAllModules() {
final SimpleModule module = new SimpleModule();
module.addSerializer(ObjectId.class, new ObjectIdSerializer());
module.addDeserializer(ObjectId.class, new ObjectIdDeserializer());
return module;
}
}

View File

@ -1,16 +0,0 @@
package org.kar.archidata.converter.jackson;
import java.io.IOException;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
public class ObjectIdDeserializer extends JsonDeserializer<ObjectId> {
@Override
public ObjectId deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
return new ObjectId(p.getValueAsString());
}
}

View File

@ -1,17 +0,0 @@
package org.kar.archidata.converter.jackson;
import java.io.IOException;
import org.bson.types.ObjectId;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class ObjectIdSerializer extends JsonSerializer<ObjectId> {
@Override
public void serialize(final ObjectId value, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeString(value.toHexString());
}
}

View File

@ -1,34 +0,0 @@
package org.kar.archidata.converter.morphia;
import java.sql.Timestamp;
import org.bson.BsonReader;
import org.bson.BsonType;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
public class SqlTimestampCodec implements Codec<Timestamp> {
@Override
public void encode(
final BsonWriter writer,
final Timestamp value,
final org.bson.codecs.EncoderContext encoderContext) {
writer.writeDateTime(value.getTime());
}
@Override
public Timestamp decode(final BsonReader reader, final org.bson.codecs.DecoderContext decoderContext) {
final BsonType bsonType = reader.getCurrentBsonType();
if (bsonType == BsonType.DATE_TIME) {
return new Timestamp(reader.readDateTime());
} else {
throw new IllegalArgumentException("Expected a DATE_TIME but found " + bsonType);
}
}
@Override
public Class<Timestamp> getEncoderClass() {
return Timestamp.class;
}
}

View File

@ -1,21 +0,0 @@
package org.kar.archidata.dataAccess;
/** Java does not permit to set return data (eg: integer) in the function parameter. This class permit to update a value as in/out function parameters. */
public class CountInOut {
// internal value of the stream
public int value = 0;
/** Default constructor */
public CountInOut() {}
/** Constructor with the initial value.
* @param i Initial Value */
public CountInOut(final int i) {
this.value = i;
}
/** Increment by one the value. */
public void inc() {
this.value++;
}
}

View File

@ -1,350 +0,0 @@
package org.kar.archidata.dataAccess;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.AnnotationTools.FieldName;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.FilterValue;
import org.kar.archidata.dataAccess.options.Limit;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.dataAccess.options.TransmitKey;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.db.DbIo;
import org.kar.archidata.db.DbIoFactory;
import org.kar.archidata.db.DbIoMorphia;
import org.kar.archidata.db.DbIoSql;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ContextGenericTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.InternalServerErrorException;
/* TODO list:
- Manage to group of SQL action to permit to commit only at the end.
*/
/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite
* back-end. */
public abstract class DBAccess implements Closeable {
final static Logger LOGGER = LoggerFactory.getLogger(DBAccess.class);
public static final DBAccess createInterface()
throws InternalServerErrorException, IOException, DataAccessException {
return DBAccess.createInterface(DbIoFactory.create());
}
public static final DBAccess createInterface(final DbConfig config)
throws InternalServerErrorException, IOException {
return DBAccess.createInterface(DbIoFactory.create(config));
}
public static final DBAccess createInterface(final DbIo io) throws InternalServerErrorException {
if (io instanceof final DbIoMorphia ioMorphia) {
try {
return new DBAccessMorphia(ioMorphia);
} catch (final IOException e) {
e.printStackTrace();
throw new InternalServerErrorException("Fail to create DB interface.");
}
} else if (io instanceof final DbIoSql ioSQL) {
try {
return new DBAccessSQL(ioSQL);
} catch (final IOException e) {
e.printStackTrace();
throw new InternalServerErrorException("Fail to create DB interface.");
}
}
throw new InternalServerErrorException("unknow DB interface ... ");
}
public boolean isDBExist(final String name, final QueryOption... option) throws InternalServerErrorException {
throw new InternalServerErrorException("Can Not manage the DB-access");
}
public boolean createDB(final String name) {
throw new InternalServerErrorException("Can Not manage the DB-access");
}
public boolean deleteDB(final String name) {
throw new InternalServerErrorException("Can Not manage the DB-access");
}
public boolean isTableExist(final String name, final QueryOption... option) throws InternalServerErrorException {
throw new InternalServerErrorException("Can Not manage the DB-access");
}
public <ID_TYPE> QueryCondition getTableIdCondition(
final Class<?> clazz,
final ID_TYPE idKey,
final QueryOptions options) throws DataAccessException {
// Find the ID field type ....
final Field idField = AnnotationTools.getIdField(clazz);
if (idField == null) {
throw new DataAccessException(
"The class have no annotation @Id ==> can not determine the default type searching");
}
// check the compatibility of the id and the declared ID
Class<?> typeClass = idField.getType();
if (idKey == null) {
throw new DataAccessException("Try to identify the ID type and object was null.");
}
final FieldName fieldName = AnnotationTools.getFieldName(idField, options);
final List<OptionSpecifyType> specificTypes = options.get(OptionSpecifyType.class);
if (typeClass == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(fieldName.inStruct())) {
typeClass = specify.clazz;
LOGGER.trace("Detect overwrite of typing ... '{}' => '{}'", typeClass.getCanonicalName(),
specify.clazz.getCanonicalName());
break;
}
}
}
if (idKey.getClass() != typeClass) {
if (idKey.getClass() == Condition.class) {
throw new DataAccessException(
"Try to identify the ID type on a condition 'close' internal API error use xxxWhere(...) instead.");
}
throw new DataAccessException("Request update with the wrong type ...");
}
return new QueryCondition(fieldName.inTable(), "=", idKey);
}
// TODO: manage insert batch...
public <T> List<T> insertMultiple(final List<T> data, final QueryOption... options) throws Exception {
final List<T> out = new ArrayList<>();
for (final T elem : data) {
final T tmp = insert(elem, options);
out.add(tmp);
}
return out;
}
abstract public <T> T insert(final T data, final QueryOption... option) throws Exception;
// seems a good idea, but very dangerous if we not filter input data... if set an id it can be complicated...
public <T> T insertWithJson(final Class<T> clazz, final String jsonData) throws Exception {
final ObjectMapper mapper = ContextGenericTools.createObjectMapper();
// parse the object to be sure the data are valid:
final T data = mapper.readValue(jsonData, clazz);
return insert(data);
}
/** Update an object with the inserted json data
*
* @param <T> Type of the object to insert
* @param <ID_TYPE> Master key on the object manage with @Id
* @param clazz Class reference of the insertion model
* @param id Key to insert data
* @param jsonData Json data (partial) values to update
* @return the number of object updated
* @throws Exception */
public <T, ID_TYPE> long updateWithJson(
final Class<T> clazz,
final ID_TYPE id,
final String jsonData,
final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
options.add(new TransmitKey(id));
return updateWhereWithJson(clazz, jsonData, options.getAllArray());
}
public <T> long updateWhereWithJson(final Class<T> clazz, final String jsonData, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
if (options.get(Condition.class).size() == 0) {
throw new DataAccessException("request a updateWhereWithJson without any condition");
}
final ObjectMapper mapper = ContextGenericTools.createObjectMapper();
// parse the object to be sure the data are valid:
final T data = mapper.readValue(jsonData, clazz);
// Read the tree to filter injection of data:
final JsonNode root = mapper.readTree(jsonData);
final List<String> keys = new ArrayList<>();
final var iterator = root.fieldNames();
iterator.forEachRemaining(e -> keys.add(e));
options.add(new FilterValue(keys));
return updateWhere(data, options.getAllArray());
}
public <T, ID_TYPE> long update(final T data, final ID_TYPE id) throws Exception {
return update(data, id, AnnotationTools.getFieldsNames(data.getClass()));
}
/** @param <T>
* @param data
* @param id
* @param filterValue
* @return the affected rows.
* @throws Exception */
public <T, ID_TYPE> long update(
final T data,
final ID_TYPE id,
final List<String> updateColomn,
final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(data.getClass(), id, options)));
options.add(new FilterValue(updateColomn));
options.add(new TransmitKey(id));
return updateWhere(data, options);
}
public <T> long updateWhere(final T data, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return updateWhere(data, options);
}
public abstract <T> long updateWhere(final T data, QueryOptions options) throws Exception;
public <T> T getWhere(final Class<T> clazz, final QueryOptions options) throws Exception {
options.add(new Limit(1));
final List<T> values = getsWhere(clazz, options);
if (values.size() == 0) {
return null;
}
return values.get(0);
}
public <T> T getWhere(final Class<T> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return getWhere(clazz, options);
}
public <T> List<T> getsWhere(final Class<T> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return getsWhere(clazz, options);
}
public Condition conditionFusionOrEmpty(final QueryOptions options, final boolean throwIfEmpty)
throws DataAccessException {
if (options == null) {
return new Condition();
}
final List<Condition> conditions = options.get(Condition.class);
if (conditions.size() == 0) {
if (throwIfEmpty) {
throw new DataAccessException("request a gets without any condition");
} else {
return new Condition();
}
}
Condition condition = null;
if (conditions.size() == 1) {
condition = conditions.get(0);
} else {
final QueryAnd andCondition = new QueryAnd();
for (final Condition cond : conditions) {
andCondition.add(cond.condition);
}
condition = new Condition(andCondition);
}
return condition;
}
abstract public <T> List<T> getsWhere(final Class<T> clazz, final QueryOptions options)
throws DataAccessException, IOException;
public <ID_TYPE> long count(final Class<?> clazz, final ID_TYPE id, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return countWhere(clazz, options);
}
public long countWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return countWhere(clazz, options);
}
public abstract long countWhere(final Class<?> clazz, final QueryOptions options) throws Exception;
public <T, ID_TYPE> T get(final Class<T> clazz, final ID_TYPE id, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return getWhere(clazz, options.getAllArray());
}
public <T> List<T> gets(final Class<T> clazz) throws Exception {
return getsWhere(clazz);
}
public <T> List<T> gets(final Class<T> clazz, final QueryOption... option) throws Exception {
return getsWhere(clazz, option);
}
/** Delete items with the specific Id (cf @Id) and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before).
* @param <ID_TYPE> Type of the reference @Id
* @param clazz Data model that might remove element
* @param id Unique Id of the model
* @param options (Optional) Options of the request
* @return Number of element that is removed. */
public <ID_TYPE> long delete(final Class<?> clazz, final ID_TYPE id, final QueryOption... options)
throws Exception {
final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
if (hasDeletedFieldName != null) {
return deleteSoft(clazz, id, options);
} else {
return deleteHard(clazz, id, options);
}
}
/** Delete items with the specific condition and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before).
* @param clazz Data model that might remove element.
* @param condition Condition to remove elements.
* @param options (Optional) Options of the request.
* @return Number of element that is removed. */
public long deleteWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final String hasDeletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
if (hasDeletedFieldName != null) {
return deleteSoftWhere(clazz, option);
} else {
return deleteHardWhere(clazz, option);
}
}
public <ID_TYPE> long deleteHard(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return deleteHardWhere(clazz, options.getAllArray());
}
public abstract long deleteHardWhere(final Class<?> clazz, final QueryOption... option) throws Exception;
public <ID_TYPE> long deleteSoft(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return deleteSoftWhere(clazz, options.getAllArray());
}
public abstract long deleteSoftWhere(final Class<?> clazz, final QueryOption... option) throws Exception;
public <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id) throws DataAccessException {
return unsetDeleteWhere(clazz, new Condition(getTableIdCondition(clazz, id, new QueryOptions())));
}
public <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws DataAccessException {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return unsetDeleteWhere(clazz, options.getAllArray());
}
public abstract long unsetDeleteWhere(final Class<?> clazz, final QueryOption... option) throws DataAccessException;
public abstract void drop(final Class<?> clazz, final QueryOption... option) throws Exception;
public abstract void cleanAll(final Class<?> clazz, final QueryOption... option) throws Exception;
}

View File

@ -1,947 +0,0 @@
package org.kar.archidata.dataAccess;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.UpdateTimestamp;
import org.kar.archidata.dataAccess.addOnMongo.AddOnManyToOne;
import org.kar.archidata.dataAccess.addOnMongo.AddOnOneToMany;
import org.kar.archidata.dataAccess.addOnMongo.DataAccessAddOn;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.FilterValue;
import org.kar.archidata.dataAccess.options.Limit;
import org.kar.archidata.dataAccess.options.OrderBy;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.db.DbIoMorphia;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.UuidUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.ReturnDocument;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.InsertOneResult;
import com.mongodb.client.result.UpdateResult;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.InternalServerErrorException;
/* TODO list:
- Manage to group of SQL action to permit to commit only at the end.
*/
/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite
* back-end. */
public class DBAccessMorphia extends DBAccess {
static final Logger LOGGER = LoggerFactory.getLogger(DBAccessMorphia.class);
// by default we manage some add-on that permit to manage non-native model (like json serialization, List of external key as String list...)
static final List<DataAccessAddOn> addOn = new ArrayList<>();
static {
//addOn.add(new AddOnManyToMany());
addOn.add(new AddOnManyToOne());
addOn.add(new AddOnOneToMany());
// no need, native support in mango .... addOn.add(new AddOnDataJson());
}
/** Add a new add-on on the current management.
* @param addOn instantiate object on the Add-on
*/
public static void addAddOn(final DataAccessAddOn addOn) {
DBAccessMorphia.addOn.add(addOn);
}
private final DbIoMorphia db;
public DBAccessMorphia(final DbIoMorphia db) throws IOException {
this.db = db;
db.open();
}
@Override
public void close() throws IOException {
this.db.close();
}
public DbIoMorphia getInterface() {
return this.db;
}
@Override
public boolean isDBExist(final String name, final QueryOption... option) throws InternalServerErrorException {
// in Mongo DB we do not need to create a DB, then we have no need to check if it exist
return true;
}
@Override
public boolean createDB(final String name) {
// in Mongo DB we do not need to create a DB
return true;
}
@Override
public boolean deleteDB(final String name) {
final MongoDatabase database = this.db.getClient().getDatabase(name);
database.drop();
return true;
}
@Override
public boolean isTableExist(final String name, final QueryOption... option) throws InternalServerErrorException {
return true;
}
public byte[][] splitIntoGroupsOf16Bytes(final byte[] input) {
final int inputLength = input.length;
final int numOfGroups = (inputLength + 15) / 16; // Calculate the number of groups needed
final byte[][] groups = new byte[numOfGroups][16];
for (int i = 0; i < numOfGroups; i++) {
final int startIndex = i * 16;
final int endIndex = Math.min(startIndex + 16, inputLength);
groups[i] = Arrays.copyOfRange(input, startIndex, endIndex);
}
return groups;
}
protected <T> void setValuedb(
final Class<?> type,
final T data,
final Field field,
final String fieldName,
final Document docSet,
final Document docUnSet) throws Exception {
if (field.get(data) == null) {
docUnSet.append(fieldName, "");
return;
}
if (type == long.class) {
docSet.append(fieldName, field.getLong(data));
return;
}
if (type == int.class) {
docSet.append(fieldName, field.getInt(data));
return;
}
if (type == float.class) {
docSet.append(fieldName, field.getFloat(data));
return;
}
if (type == Double.class) {
docSet.append(fieldName, field.getDouble(data));
return;
}
if (type == boolean.class) {
docSet.append(fieldName, field.getBoolean(data));
return;
}
final Object tmp = field.get(data);
if (tmp == null) {
docUnSet.append(fieldName, "");
return;
}
if (type.isEnum()) {
docSet.append(fieldName, tmp.toString());
return;
}
if (type == Long.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Integer.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Float.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Double.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Boolean.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == String.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Timestamp.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == UUID.class) {
docSet.append(fieldName, tmp);
return;
}
if (type == Date.class) {
// TODO ...
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final Timestamp sqlDate = java.sql.Timestamp.from(((Date) tmp).toInstant());
ps.setTimestamp(iii.value, sqlDate);
}*/
}
if (type == Instant.class) {
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final String sqlDate = ((Instant) tmp).toString();
ps.setString(iii.value, sqlDate);
}
*/
}
if (type == LocalDate.class) {
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final java.sql.Date sqlDate = java.sql.Date.valueOf((LocalDate) tmp);
ps.setDate(iii.value, sqlDate);
}
*/
}
if (type == LocalTime.class) {
/*
final Object tmp = field.get(data);
if (tmp == null) {
ps.setNull(iii.value, Types.INTEGER);
} else {
final java.sql.Time sqlDate = java.sql.Time.valueOf((LocalTime) tmp);
ps.setTime(iii.value, sqlDate);
}
*/
}
throw new DataAccessException("Unknown Field Type");
}
public <T> void setValueFromDoc(
final Class<?> type,
final Object data,
final Field field,
final Document doc,
final List<LazyGetter> lazyCall,
final QueryOptions options) throws Exception {
final String fieldName = AnnotationTools.getFieldName(field, options).inTable();
if (!doc.containsKey(fieldName)) {
field.set(data, null);
return;
}
if (type == UUID.class) {
final UUID value = doc.get(fieldName, UUID.class);
field.set(data, value);
return;
}
if (type == Long.class || type == long.class) {
final Long value = doc.getLong(fieldName);
field.set(data, value);
return;
}
if (type == Integer.class || type == int.class) {
final Integer value = doc.getInteger(fieldName);
field.set(data, value);
return;
}
if (type == Float.class || type == float.class) {
final Double value = doc.getDouble(fieldName);
field.set(data, (float) ((double) value));
return;
}
if (type == Double.class || type == double.class) {
final Double value = doc.getDouble(fieldName);
field.set(data, value);
return;
}
if (type == Boolean.class || type == boolean.class) {
final Boolean value = doc.getBoolean(fieldName);
field.set(data, value);
return;
}
if (type == Timestamp.class) {
final Date value = doc.get(fieldName, Date.class);
final Timestamp newData = new Timestamp(value.getTime());
field.set(data, newData);
return;
}
if (type == Date.class) {
final Date value = doc.get(fieldName, Date.class);
field.set(data, value);
return;
}
if (type == Instant.class) {
final Date value = doc.get(fieldName, Date.class);
final Instant newData = value.toInstant();
field.set(data, newData);
return;
}
if (type == LocalDate.class) {
final Date value = doc.get(fieldName, Date.class);
final LocalDate newData = value.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
field.set(data, newData);
return;
}
if (type == LocalTime.class) {
final Long value = doc.getLong(fieldName);
final LocalTime newData = LocalTime.ofNanoOfDay(value);
field.set(data, newData);
return;
}
if (type == String.class) {
final String value = doc.getString(fieldName);
field.set(data, value);
return;
}
if (type == UUID.class) {
final Object value = doc.get(fieldName, field.getType());
field.set(data, value);
return;
}
if (type.isEnum()) {
final String value = doc.getString(fieldName);
boolean find = false;
final Object[] arr = type.getEnumConstants();
for (final Object elem : arr) {
if (elem.toString().equals(value)) {
field.set(data, elem);
find = true;
break;
}
}
if (!find) {
throw new DataAccessException("Enum value does not exist in the Model: '" + value + "'");
}
return;
}
if (List.class == field.getType()) {
final Object value = doc.get(fieldName, field.getType());
field.set(data, value);
} else {
final Object value = createObjectFromDocument(doc.get(fieldName, Document.class), field.getType(), null,
lazyCall);
field.set(data, value);
}
return;
//throw new ArchiveException("wrong type of field [" + fieldName + "]: " + doc.toJson());
}
protected Object convertDefaultField(String data, final Field field) throws Exception {
if (data.startsWith("'") && data.endsWith("'")) {
data = data.substring(1, data.length() - 1);
}
final Class<?> type = field.getType();
if (type == UUID.class) {
}
if (type == Long.class || type == long.class) {
return Long.parseLong(data);
}
if (type == Integer.class || type == int.class) {
return Integer.parseInt(data);
}
if (type == Float.class || type == float.class) {
return Float.parseFloat(data);
}
if (type == Double.class || type == double.class) {
return Double.parseDouble(data);
}
if (type == Boolean.class || type == boolean.class) {
return Boolean.parseBoolean(data);
}
if (type == Timestamp.class) {}
if (type == Date.class) {}
if (type == Instant.class) {}
if (type == LocalDate.class) {}
if (type == LocalTime.class) {}
if (type == String.class) {}
if (type.isEnum()) {
final boolean find = false;
final Object[] arr = type.getEnumConstants();
for (final Object elem : arr) {
if (elem.toString().equals(data)) {
return elem;
}
}
if (!find) {
throw new DataAccessException("Enum value does not exist in the Model: '" + data + "'");
}
}
LOGGER.warn("Request default of unknow native type {} => {}", type.getCanonicalName(), data);
return null;
}
public boolean isAddOnField(final Field field) {
return findAddOnforField(field) != null;
}
public DataAccessAddOn findAddOnforField(final Field field) {
for (final DataAccessAddOn elem : addOn) {
if (elem.isCompatibleField(field)) {
return elem;
}
}
return null;
}
public long getNextSequenceLongValue(final String collectionName, String fieldName) {
if (fieldName == null || fieldName.isEmpty()) {
fieldName = "sequence_id";
}
// Collection "counters" to store the sequences if Ids
final MongoCollection<Document> countersCollection = this.db.getDatastore().getDatabase()
.getCollection("counters");
// Filter to find the specific counter for the collections
final Document filter = new Document("_id", collectionName);
// Update the field <fieldName> of 1
final Document update = new Document("$inc", new Document(fieldName, 1L));
// get the value after updated it
final FindOneAndUpdateOptions options = new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
.upsert(true); // create field if not exist
// Real creation of the unique counter.
final Document updatedCounter = countersCollection.findOneAndUpdate(filter, update, options);
// Return the new sequence value...
return updatedCounter.getLong(fieldName);
}
@Override
@SuppressWarnings("unchecked")
public <T> T insert(final T data, final QueryOption... option) throws Exception {
final Class<?> clazz = data.getClass();
final QueryOptions options = new QueryOptions(option);
// External checker of data:
final List<CheckFunction> checks = options.get(CheckFunction.class);
for (final CheckFunction check : checks) {
check.getChecker().check(this, "", data, AnnotationTools.getFieldsNames(clazz), options);
}
final List<Field> asyncFieldUpdate = new ArrayList<>();
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
Field primaryKeyField = null;
Object uniqueId = null;
// real add in the BDD:
ObjectId insertedId = null;
try {
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase()
.getCollection(collectionName);
final Document doc = new Document();
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
final String tableFieldName = AnnotationTools.getFieldName(field, options).inTable();
Object currentInsertValue = field.get(data);
if (AnnotationTools.isPrimaryKey(field)) {
primaryKeyField = field;
if (primaryKeyField.getType() == UUID.class) {
final UUID uuid = UuidUtils.nextUUID();
uniqueId = uuid;
doc.append(tableFieldName, uuid);
continue;
} else if (primaryKeyField.getType() == Long.class || primaryKeyField.getType() == long.class) {
// By default the MongoDB does not manage the
final long id = getNextSequenceLongValue(collectionName, tableFieldName);
uniqueId = id;
doc.append(tableFieldName, id);
continue;
}
LOGGER.error("TODO: Manage the ID primary key for type: ");
continue;
}
final DataAccessAddOn addOn = findAddOnforField(field);
if (addOn != null && !addOn.canInsert(field)) {
if (addOn.isInsertAsync(field)) {
LOGGER.error("TODO: add async objects ...");
//asyncFieldUpdate.add(field);
}
continue;
}
final boolean createTime = field.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
if (createTime) {
doc.append(tableFieldName, Date.from(Instant.now()));
continue;
}
final boolean updateTime = field.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
if (updateTime) {
doc.append(tableFieldName, Date.from(Instant.now()));
continue;
}
if (currentInsertValue == null && !field.getClass().isPrimitive()) {
final DefaultValue[] defaultValue = field.getDeclaredAnnotationsByType(DefaultValue.class);
LOGGER.error("TODO: convert default value in the correct value for the DB...");
if (defaultValue.length == 0) {
continue;
} else {
final String value = defaultValue[0].value();
if (value == null) {
continue;
}
currentInsertValue = convertDefaultField(value, field);
}
}
doc.append(tableFieldName, currentInsertValue);
}
final InsertOneResult result = collection.insertOne(doc);
// Get the Object of inserted object:
insertedId = result.getInsertedId().asObjectId().getValue();
LOGGER.info("Document inserted with ID: " + insertedId);
// Rechercher et récupérer le document inséré à partir de son ObjectId
final Document insertedDocument = collection.find(new Document("_id", insertedId)).first();
// Afficher le document récupéré
LOGGER.trace("Inserted document: " + insertedDocument);
} catch (final Exception ex) {
LOGGER.error("Fail SQL request: {}", ex.getMessage());
ex.printStackTrace();
throw new DataAccessException("Fail to Insert data in DB : " + ex.getMessage());
}
final List<LazyGetter> asyncActions = new ArrayList<>();
for (final Field field : asyncFieldUpdate) {
final DataAccessAddOn addOn = findAddOnforField(field);
if (uniqueId instanceof final Long id) {
LOGGER.error("TODO: Add on not managed .1. ");
//addOn.asyncInsert(tableName, id, field, field.get(data), asyncActions);
} else if (uniqueId instanceof final UUID uuid) {
LOGGER.error("TODO: Add on not managed .2. ");
//addOn.asyncInsert(tableName, uuid, field, field.get(data), asyncActions);
}
}
for (final LazyGetter action : asyncActions) {
action.doRequest();
}
return (T) getWhere(clazz, new Condition(new QueryCondition("_id", "=", insertedId)));
}
@Override
public <T> long updateWhere(final T data, QueryOptions options) throws Exception {
final Class<?> clazz = data.getClass();
if (options == null) {
options = new QueryOptions();
}
final Condition condition = conditionFusionOrEmpty(options, true);
final List<FilterValue> filterKeys = options != null ? options.get(FilterValue.class) : new ArrayList<>();
if (filterKeys.size() != 1) {
throw new DataAccessException("request a gets without/or with more 1 filter of values");
}
final FilterValue filterKey = filterKeys.get(0);
// External checker of data:
if (options != null) {
final List<CheckFunction> checks = options.get(CheckFunction.class);
for (final CheckFunction check : checks) {
check.getChecker().check(this, "", data, filterKey.getValues(), options);
}
}
final List<LazyGetter> asyncActions = new ArrayList<>();
// real add in the BDD:
try {
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
final Document docSet = new Document();
final Document docUnSet = new Document();
for (final Field field : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue;
}
final String fieldName = AnnotationTools.getFieldName(field, options).inTable();
// update field is not conditioned by filter:
final boolean updateTime = field.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
if (updateTime) {
docSet.append(fieldName, Date.from(Instant.now()));
continue;
}
if (!filterKey.getValues().contains(fieldName)) {
continue;
} else if (AnnotationTools.isGenericField(field)) {
continue;
}
final DataAccessAddOn addOn = findAddOnforField(field);
if (addOn != null && !addOn.canInsert(field)) {
if (addOn.isInsertAsync(field)) {
LOGGER.error("TODO: Add on not managed .3. ");
/*
final List<TransmitKey> transmitKey = options.get(TransmitKey.class);
if (transmitKey.size() != 1) {
throw new DataAccessException(
"Fail to transmit Key to update the async update... (must have only 1)");
}
addOn.asyncUpdate(tableName, transmitKey.get(0).getKey(), field, field.get(data), asyncActions);
*/
}
continue;
}
if (addOn != null) {
addOn.insertData(this, field, data, options, docSet, docUnSet);
} else {
final Class<?> type = field.getType();
if (!type.isPrimitive()) {
final Object tmp = field.get(data);
if (tmp == null && field.getDeclaredAnnotationsByType(DefaultValue.class).length != 0) {
continue;
}
}
setValuedb(type, data, field, fieldName, docSet, docUnSet);
}
}
// Do the query ...
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase()
.getCollection(collectionName);
final Document actions = new Document();
if (!docSet.isEmpty()) {
actions.append("$set", docSet);
}
if (!docUnSet.isEmpty()) {
actions.append("$unset", docUnSet);
}
LOGGER.info("updateWhere with value: {}", actions.toJson());
final UpdateResult ret = collection.updateMany(filters, actions);
return ret.getModifiedCount();
} catch (final Exception ex) {
ex.printStackTrace();
}
for (final LazyGetter action : asyncActions) {
action.doRequest();
}
return 0;
}
public List<String> generateSelectField(final Class<?> clazz, final QueryOptions options) throws Exception {
// TODO: list of user select fields.
final boolean readAllfields = QueryOptions.readAllColomn(options);
final List<String> fieldsName = new ArrayList<>();
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
final boolean notRead = AnnotationTools.isDefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}
final String name = AnnotationTools.getFieldName(elem, options).inTable();
fieldsName.add(name);
}
return fieldsName;
}
@Override
public Condition conditionFusionOrEmpty(final QueryOptions options, final boolean throwIfEmpty)
throws DataAccessException {
if (options == null) {
return new Condition();
}
final List<Condition> conditions = options.get(Condition.class);
if (conditions.size() == 0) {
if (throwIfEmpty) {
throw new DataAccessException("request a gets without any condition");
} else {
return new Condition();
}
}
Condition condition = null;
if (conditions.size() == 1) {
condition = conditions.get(0);
} else {
final QueryAnd andCondition = new QueryAnd();
for (final Condition cond : conditions) {
andCondition.add(cond.condition);
}
condition = new Condition(andCondition);
}
return condition;
}
@Override
@SuppressWarnings("unchecked")
public <T> List<T> getsWhere(final Class<T> clazz, final QueryOptions options)
throws DataAccessException, IOException {
final Condition condition = conditionFusionOrEmpty(options, false);
final List<LazyGetter> lazyCall = new ArrayList<>();
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final List<T> outs = new ArrayList<>();
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
try {
// Generate the filtering of the data:
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
FindIterable<Document> retFind = null;
if (filters != null) {
//LOGGER.info("getsWhere Find filter: {}", filters.toBsonDocument().toJson());
retFind = collection.find(filters);
} else {
retFind = collection.find();
}
/* Not manage right now ...
final List<GroupBy> groups = options.get(GroupBy.class);
for (final GroupBy group : groups) {
group.generateQuery(query, tableName);
}
*/
final List<OrderBy> orders = options.get(OrderBy.class);
if (orders.size() != 0) {
final Document sorts = new Document();
for (final OrderBy order : orders) {
order.generateSort(sorts);
}
retFind = retFind.sort(sorts);
}
final List<Limit> limits = options.get(Limit.class);
if (limits.size() == 1) {
retFind = retFind.limit((int) limits.get(0).getValue());
} else if (limits.size() > 1) {
throw new DataAccessException("Request with multiple 'limit'...");
}
// Select values to read
final List<String> listFields = generateSelectField(clazz, options);
listFields.add("_id");
retFind = retFind.projection(Projections.include(listFields.toArray(new String[0])));
LOGGER.info("GetsWhere ...");
final MongoCursor<Document> cursor = retFind.iterator();
try (cursor) {
while (cursor.hasNext()) {
final Document doc = cursor.next();
LOGGER.info(" - getWhere value: {}", doc.toJson());
final Object data = createObjectFromDocument(doc, clazz, options, lazyCall);
final T out = (T) data;
outs.add(out);
}
LOGGER.info("Async calls: {}", lazyCall.size());
for (final LazyGetter elem : lazyCall) {
elem.doRequest();
}
}
} catch (final Exception ex) {
ex.printStackTrace();
throw new DataAccessException("Catch an Exception: " + ex.getMessage());
}
return outs;
}
public Object createObjectFromDocument(
final Document doc,
final Class<?> clazz,
final QueryOptions options,
final List<LazyGetter> lazyCall) throws Exception {
final boolean readAllfields = QueryOptions.readAllColomn(options);
// TODO: manage class that is defined inside a class ==> Not manage for now...
Object data = null;
for (final Constructor<?> contructor : clazz.getConstructors()) {
if (contructor.getParameterCount() == 0) {
data = contructor.newInstance();
break;
}
}
if (data == null) {
throw new DataAccessException(
"Can not find the default constructor for the class: " + clazz.getCanonicalName());
}
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
final DataAccessAddOn addOn = findAddOnforField(elem);
if (addOn != null && !addOn.canRetrieve(elem)) {
continue;
}
final boolean notRead = AnnotationTools.isDefaultNotRead(elem);
if (!readAllfields && notRead) {
continue;
}
if (addOn != null) {
LOGGER.error("TODO: Add on not managed .6. ");
addOn.fillFromDoc(this, doc, elem, data, options, lazyCall);
} else {
setValueFromDoc(elem.getType(), data, elem, doc, lazyCall, options);
}
}
return data;
}
@Override
public <ID_TYPE> long count(final Class<?> clazz, final ID_TYPE id, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return this.countWhere(clazz, options);
}
@Override
public long countWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return countWhere(clazz, options);
}
@Override
public long countWhere(final Class<?> clazz, final QueryOptions options) throws Exception {
final Condition condition = conditionFusionOrEmpty(options, false);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
try {
// Generate the filtering of the data:
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
if (filters != null) {
return collection.countDocuments(filters);
}
return collection.countDocuments();
} catch (final Exception ex) {
ex.printStackTrace();
throw new DataAccessException("Catch an Exception: " + ex.getMessage());
}
}
@Override
public <T, ID_TYPE> T get(final Class<T> clazz, final ID_TYPE id, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return this.getWhere(clazz, options.getAllArray());
}
@Override
public <ID_TYPE> long deleteHard(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return deleteHardWhere(clazz, options.getAllArray());
}
@Override
public long deleteHardWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final Condition condition = conditionFusionOrEmpty(options, true);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
DeleteResult retFind;
if (filters != null) {
retFind = collection.deleteMany(filters);
} else {
throw new DataAccessException("Too dangerout to delete element with no filter values !!!");
}
return retFind.getDeletedCount();
}
@Override
public <ID_TYPE> long deleteSoft(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws Exception {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return deleteSoftWhere(clazz, options.getAllArray());
}
@Override
public long deleteSoftWhere(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final Condition condition = conditionFusionOrEmpty(options, true);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
final Document actions = new Document("$set", new Document(deletedFieldName, true));
LOGGER.info("update some values: {}", actions.toJson());
final UpdateResult ret = collection.updateMany(filters, actions);
return ret.getModifiedCount();
}
@Override
public <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id) throws DataAccessException {
return unsetDeleteWhere(clazz, new Condition(getTableIdCondition(clazz, id, new QueryOptions())));
}
@Override
public <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id, final QueryOption... option)
throws DataAccessException {
final QueryOptions options = new QueryOptions(option);
options.add(new Condition(getTableIdCondition(clazz, id, options)));
return unsetDeleteWhere(clazz, options.getAllArray());
}
@Override
public long unsetDeleteWhere(final Class<?> clazz, final QueryOption... option) throws DataAccessException {
final QueryOptions options = new QueryOptions(option);
final Condition condition = conditionFusionOrEmpty(options, true);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz);
if (deletedFieldName == null) {
throw new DataAccessException("The class " + clazz.getCanonicalName() + " has no deleted field");
}
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
final Bson filters = condition.getFilter(collectionName, options, deletedFieldName);
final Document actions = new Document("$set", new Document(deletedFieldName, false));
LOGGER.info("update some values: {}", actions.toJson());
final UpdateResult ret = collection.updateMany(filters, actions);
return ret.getModifiedCount();
}
@Override
public void drop(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
collection.drop();
}
@Override
public void cleanAll(final Class<?> clazz, final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
final String collectionName = AnnotationTools.getCollectionName(clazz, options);
final MongoCollection<Document> collection = this.db.getDatastore().getDatabase().getCollection(collectionName);
collection.deleteMany(new Document());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,294 +0,0 @@
package org.kar.archidata.dataAccess;
import java.io.IOException;
import java.util.List;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.exception.DataAccessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.ws.rs.InternalServerErrorException;
/* TODO list:
- Manage to group of SQL action to permit to commit only at the end.
*/
/** Data access is an abstraction class that permit to access on the DB with a function wrapping that permit to minimize the SQL writing of SQL code. This interface support the SQL and SQLite
* back-end. */
public class DataAccess {
private static final Logger LOGGER = LoggerFactory.getLogger(DataAccess.class);
public DataAccess() {
}
public static boolean isDBExist(final String name, final QueryOption... options)
throws InternalServerErrorException, IOException, DataAccessException {
try (DBAccess db = DBAccess.createInterface()) {
return db.isDBExist(name, options);
}
}
public static boolean createDB(final String name)
throws IOException, InternalServerErrorException, DataAccessException {
try (DBAccess db = DBAccess.createInterface()) {
return db.createDB(name);
}
}
public static boolean isTableExist(final String name, final QueryOption... options)
throws InternalServerErrorException, IOException, DataAccessException {
try (DBAccess db = DBAccess.createInterface()) {
return db.isTableExist(name, options);
}
}
// TODO: manage insert batch...
public static <T> List<T> insertMultiple(final List<T> data, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.insertMultiple(data, options);
}
}
@SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING")
public static <T> T insert(final T data, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.insert(data, options);
}
}
// seems a good idea, but very dangerous if we not filter input data... if set an id it can be complicated...
public static <T> T insertWithJson(final Class<T> clazz, final String jsonData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.insertWithJson(clazz, jsonData);
}
}
public static <ID_TYPE> QueryCondition getTableIdCondition(
final Class<?> clazz,
final ID_TYPE idKey,
final QueryOptions options) throws DataAccessException, IOException {
try (DBAccess db = DBAccess.createInterface()) {
return db.getTableIdCondition(clazz, idKey, options);
}
}
/** Update an object with the inserted json data
*
* @param <T> Type of the object to insert
* @param <ID_TYPE> Master key on the object manage with @Id
* @param clazz Class reference of the insertion model
* @param id Key to insert data
* @param jsonData Json data (partial) values to update
* @return the number of object updated
* @throws Exception */
public static <T, ID_TYPE> long updateWithJson(
final Class<T> clazz,
final ID_TYPE id,
final String jsonData,
final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.updateWithJson(clazz, id, jsonData, options);
}
}
public static <T> long updateWhereWithJson(
final Class<T> clazz,
final String jsonData,
final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.updateWhereWithJson(clazz, jsonData, options);
}
}
public static <T, ID_TYPE> long update(final T data, final ID_TYPE id) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.update(data, id);
}
}
/** @param <T>
* @param data
* @param id
* @param filterValue
* @return the affected rows.
* @throws Exception */
public static <T, ID_TYPE> long update(
final T data,
final ID_TYPE id,
final List<String> updateColomn,
final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.update(data, id, updateColomn, options);
}
}
public static <T> long updateWhere(final T data, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.updateWhere(data, options);
}
}
public static <T> long updateWhere(final T data, final QueryOptions options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.updateWhere(data, options);
}
}
public static <T> T getWhere(final Class<T> clazz, final QueryOptions options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.getWhere(clazz, options);
}
}
public static <T> T getWhere(final Class<T> clazz, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.getWhere(clazz, options);
}
}
public static <T> List<T> getsWhere(final Class<T> clazz, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.getsWhere(clazz, options);
}
}
public static Condition conditionFusionOrEmpty(final QueryOptions options, final boolean throwIfEmpty)
throws DataAccessException, IOException {
try (DBAccess db = DBAccess.createInterface()) {
return db.conditionFusionOrEmpty(options, throwIfEmpty);
}
}
public static <T> List<T> getsWhere(final Class<T> clazz, final QueryOptions options)
throws DataAccessException, IOException {
try (DBAccess db = DBAccess.createInterface()) {
return db.getsWhere(clazz, options);
}
}
public static <ID_TYPE> long count(final Class<?> clazz, final ID_TYPE id, final QueryOption... options)
throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.count(clazz, id, options);
}
}
public static long countWhere(final Class<?> clazz, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.countWhere(clazz, options);
}
}
public static long countWhere(final Class<?> clazz, final QueryOptions options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.countWhere(clazz, options);
}
}
public static <T, ID_TYPE> T get(final Class<T> clazz, final ID_TYPE id, final QueryOption... options)
throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.get(clazz, id, options);
}
}
public static <T> List<T> gets(final Class<T> clazz) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.gets(clazz);
}
}
public static <T> List<T> gets(final Class<T> clazz, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.gets(clazz, options);
}
}
/** Delete items with the specific Id (cf @Id) and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before).
* @param <ID_TYPE> Type of the reference @Id
* @param clazz Data model that might remove element
* @param id Unique Id of the model
* @param options (Optional) Options of the request
* @return Number of element that is removed. */
public static <ID_TYPE> long delete(final Class<?> clazz, final ID_TYPE id, final QueryOption... options)
throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.delete(clazz, id, options);
}
}
/** Delete items with the specific condition and some options. If the Entity is manage as a softDeleted model, then it is flag as removed (if not already done before).
* @param clazz Data model that might remove element.
* @param condition Condition to remove elements.
* @param options (Optional) Options of the request.
* @return Number of element that is removed. */
public static long deleteWhere(final Class<?> clazz, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.deleteWhere(clazz, options);
}
}
public static <ID_TYPE> long deleteHard(final Class<?> clazz, final ID_TYPE id, final QueryOption... options)
throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.deleteHard(clazz, id, options);
}
}
public static long deleteHardWhere(final Class<?> clazz, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.deleteHardWhere(clazz, options);
}
}
public static <ID_TYPE> long deleteSoft(final Class<?> clazz, final ID_TYPE id, final QueryOption... options)
throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.deleteSoft(clazz, id, options);
}
}
public static long deleteSoftWhere(final Class<?> clazz, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
return db.deleteSoftWhere(clazz, options);
}
}
public static <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id)
throws DataAccessException, IOException {
try (DBAccess db = DBAccess.createInterface()) {
return db.unsetDelete(clazz, id);
}
}
public static <ID_TYPE> long unsetDelete(final Class<?> clazz, final ID_TYPE id, final QueryOption... options)
throws DataAccessException, IOException {
try (DBAccess db = DBAccess.createInterface()) {
return db.unsetDelete(clazz, id, options);
}
}
public static long unsetDeleteWhere(final Class<?> clazz, final QueryOption... options)
throws DataAccessException, IOException {
try (DBAccess db = DBAccess.createInterface()) {
return db.unsetDeleteWhere(clazz, options);
}
}
public static void drop(final Class<?> clazz, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
db.drop(clazz, options);
}
}
public static void cleanAll(final Class<?> clazz, final QueryOption... options) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
db.cleanAll(clazz, options);
}
}
}

View File

@ -1,413 +0,0 @@
package org.kar.archidata.dataAccess;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.dataAccess.exportTools.TableQuery;
import org.kar.archidata.dataAccess.exportTools.TableQueryTypes;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.GroupBy;
import org.kar.archidata.dataAccess.options.Limit;
import org.kar.archidata.dataAccess.options.OrderBy;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ContextGenericTools;
import org.kar.archidata.tools.DateTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
public class DataExport {
static final Logger LOGGER = LoggerFactory.getLogger(DataExport.class);
public static final String CSV_TYPE = "text/csv";
@SuppressWarnings("unchecked")
protected static RetreiveFromDB createSetValueFromDbCallbackTable(
final int count,
final Class<?> type,
final int id) throws Exception {
if (type == UUID.class) {
return (final ResultSet rs, final Object obj) -> {
final UUID tmp = rs.getObject(count, UUID.class);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Long.class) {
return (final ResultSet rs, final Object obj) -> {
final Long tmp = rs.getLong(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == long.class) {
return (final ResultSet rs, final Object obj) -> {
final Long tmp = rs.getLong(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Integer.class) {
return (final ResultSet rs, final Object obj) -> {
final Integer tmp = rs.getInt(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == int.class) {
return (final ResultSet rs, final Object obj) -> {
final Integer tmp = rs.getInt(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Float.class) {
return (final ResultSet rs, final Object obj) -> {
final Float tmp = rs.getFloat(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == float.class) {
return (final ResultSet rs, final Object obj) -> {
final Float tmp = rs.getFloat(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Double.class) {
return (final ResultSet rs, final Object obj) -> {
final Double tmp = rs.getDouble(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == double.class) {
return (final ResultSet rs, final Object obj) -> {
final Double tmp = rs.getDouble(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Boolean.class) {
return (final ResultSet rs, final Object obj) -> {
final Boolean tmp = rs.getBoolean(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == boolean.class) {
return (final ResultSet rs, final Object obj) -> {
final Boolean tmp = rs.getBoolean(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Timestamp.class) {
return (final ResultSet rs, final Object obj) -> {
final Timestamp tmp = rs.getTimestamp(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type == Date.class) {
return (final ResultSet rs, final Object obj) -> {
try {
final Timestamp tmp = rs.getTimestamp(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, Date.from(tmp.toInstant()));
}
} catch (final SQLException ex) {
final String tmp = rs.getString(count);
LOGGER.error("Fail to parse the SQL time !!! {}", tmp);
if (!rs.wasNull()) {
final Date date = DateTools.parseDate(tmp);
LOGGER.error("Fail to parse the SQL time !!! {}", date);
final List<Object> data = (List<Object>) (obj);
data.set(id, date);
}
}
};
}
if (type == Instant.class) {
return (final ResultSet rs, final Object obj) -> {
final String tmp = rs.getString(count);
if (!rs.wasNull()) {
final Instant date = Instant.parse(tmp);
LOGGER.error("Fail to parse the SQL time !!! {}", date);
final List<Object> data = (List<Object>) (obj);
data.set(id, date);
}
};
}
if (type == LocalDate.class) {
return (final ResultSet rs, final Object obj) -> {
final java.sql.Date tmp = rs.getDate(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp.toLocalDate());
}
};
}
if (type == LocalTime.class) {
return (final ResultSet rs, final Object obj) -> {
final java.sql.Time tmp = rs.getTime(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp.toLocalTime());
}
};
}
if (type == String.class) {
return (final ResultSet rs, final Object obj) -> {
final String tmp = rs.getString(count);
if (!rs.wasNull()) {
final List<Object> data = (List<Object>) (obj);
data.set(id, tmp);
}
};
}
if (type.isEnum()) {
return (final ResultSet rs, final Object obj) -> {
final String tmp = rs.getString(count);
if (!rs.wasNull()) {
boolean find = false;
final Object[] arr = type.getEnumConstants();
for (final Object elem : arr) {
if (elem.toString().equals(tmp)) {
final List<Object> data = (List<Object>) (obj);
data.set(id, elem);
find = true;
break;
}
}
if (!find) {
throw new DataAccessException("Enum value does not exist in the Model: '" + tmp + "'");
}
}
};
}
throw new DataAccessException("Unknown Field Type");
}
private static int getQueryPropertyId(final List<TableQueryTypes> properties, final String name)
throws DataAccessException {
for (int iii = 0; iii < properties.size(); iii++) {
if (properties.get(iii).name.equals(name)) {
return iii;
}
}
throw new DataAccessException("Query with unknown field: '" + name + "'");
}
public static TableQuery queryTable(
final DBAccessSQL ioDb,
final List<TableQueryTypes> headers,
final String query,
final List<Object> parameters,
final QueryOption... option) throws Exception {
final QueryOptions options = new QueryOptions(option);
return queryTable(ioDb, headers, query, parameters, options);
}
public static TableQuery queryTable(
final DBAccessSQL ioDb,
final List<TableQueryTypes> headers,
final String queryBase,
final List<Object> parameters,
final QueryOptions options) throws Exception {
final List<LazyGetter> lazyCall = new ArrayList<>();
final Condition condition = ioDb.conditionFusionOrEmpty(options, false);
final StringBuilder query = new StringBuilder(queryBase);
final TableQuery out = new TableQuery(headers);
// real add in the BDD:
try {
final CountInOut count = new CountInOut();
condition.whereAppendQuery(query, null, options, null);
final List<GroupBy> groups = options.get(GroupBy.class);
for (final GroupBy group : groups) {
group.generateQuery(query, null);
}
final List<OrderBy> orders = options.get(OrderBy.class);
for (final OrderBy order : orders) {
order.generateQuery(query, null);
}
final List<Limit> limits = options.get(Limit.class);
if (limits.size() == 1) {
limits.get(0).generateQuery(query, null);
} else if (limits.size() > 1) {
throw new DataAccessException("Request with multiple 'limit'...");
}
LOGGER.warn("generate the query: '{}'", query.toString());
// prepare the request:
final PreparedStatement ps = ioDb.getConnection().prepareStatement(query.toString(),
Statement.RETURN_GENERATED_KEYS);
final CountInOut iii = new CountInOut(1);
if (parameters != null) {
for (final Object elem : parameters) {
ioDb.addElement(ps, elem, iii);
}
iii.inc();
}
condition.injectQuery(ioDb, ps, iii);
if (limits.size() == 1) {
limits.get(0).injectQuery(ioDb, ps, iii);
}
// execute the request
final ResultSet rs = ps.executeQuery();
final ResultSetMetaData rsmd = rs.getMetaData();
final List<RetreiveFromDB> actionToRetreive = new ArrayList<>();
LOGGER.info("Field:");
for (int jjj = 0; jjj < rsmd.getColumnCount(); jjj++) {
final String label = rsmd.getColumnLabel(jjj + 1);
final String typeName = rsmd.getColumnTypeName(jjj + 1);
final int typeId = rsmd.getColumnType(jjj + 1);
final int id = getQueryPropertyId(headers, label);
LOGGER.info(" - {}:{} type=[{}] {} REQUEST={}", jjj, label, typeId, typeName,
headers.get(id).type.getCanonicalName());
// create the callback...
final RetreiveFromDB element = createSetValueFromDbCallbackTable(jjj + 1, headers.get(id).type, id);
actionToRetreive.add(element);
}
while (rs.next()) {
count.value = 1;
final List<Object> data = Arrays.asList(new Object[headers.size()]);
for (final RetreiveFromDB action : actionToRetreive) {
action.doRequest(rs, data);
}
out.values.add(data);
}
LOGGER.info("Async calls: {}", lazyCall.size());
for (final LazyGetter elem : lazyCall) {
elem.doRequest();
}
} catch (final SQLException ex) {
ex.printStackTrace();
throw ex;
} catch (final Exception ex) {
ex.printStackTrace();
}
return out;
}
public static String CSVReplaceSeparator(final String data, final String separator) {
if (data == null) {
return "";
}
final String separatorLine = "\n";
final String separatorLineReplace = "\\n";
return data.replaceAll(separator, "__SEP__").replaceAll(separatorLine, separatorLineReplace);
}
public static String tableToCSV(final TableQuery data) {
final String separator = ";";
final StringBuilder out = new StringBuilder();
// generate header:
boolean first = true;
for (final TableQueryTypes elem : data.headers) {
if (!first) {
out.append(separator);
} else {
first = false;
}
out.append(CSVReplaceSeparator(elem.title, separator));
}
out.append("\n");
// generate body:
first = true;
for (final List<Object> line : data.values) {
for (final Object elem : line) {
if (!first) {
out.append(separator);
} else {
first = false;
}
if (elem != null) {
out.append(CSVReplaceSeparator(elem.toString(), separator));
}
}
out.append("\n");
}
return out.toString();
}
public static Response convertInResponse(final TableQuery dataOut, final String accept)
throws DataAccessException, IOException {
if (CSV_TYPE.equals(accept)) {
// CSV serialization
String out = null;
try {
out = DataExport.tableToCSV(dataOut);
} catch (final Exception e) {
LOGGER.error("Fail to generate CSV....");
e.printStackTrace();
throw new DataAccessException("Fail in CSV convertion data");
}
return Response.ok(out).header("Content-Type", CSV_TYPE).build();
}
if (MediaType.APPLICATION_JSON.equals(accept)) {
LOGGER.info("Start mapping josn");
final ObjectMapper objectMapper = ContextGenericTools.createObjectMapper();
LOGGER.info("Start find modules josn");
objectMapper.findAndRegisterModules();
LOGGER.info("Start map object");
String out;
try {
out = objectMapper.writeValueAsString(dataOut);
} catch (final JsonProcessingException e) {
LOGGER.error("Fail to generate JSON....");
e.printStackTrace();
throw new DataAccessException("Fail in JSON convertion data");
}
LOGGER.info("generate response");
return Response.ok(out).header("Content-Type", MediaType.APPLICATION_JSON).build();
}
throw new IOException("This type is not managed: '" + accept + "'");
}
}

View File

@ -1,476 +0,0 @@
package org.kar.archidata.dataAccess;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.AnnotationTools;
import org.kar.archidata.annotation.CreationTimestamp;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.UpdateTimestamp;
import org.kar.archidata.dataAccess.addOnSQL.DataAccessAddOn;
import org.kar.archidata.dataAccess.options.CreateDropTable;
import org.kar.archidata.dataAccess.options.OptionSpecifyType;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.persistence.GenerationType;
public class DataFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class);
public static String convertTypeInSQL(final Class<?> type, final String fieldName) throws DataAccessException {
final String typelocal = ConfigBaseVariable.getDBType();
if ("mysql".equals(typelocal)) {
if (type == UUID.class) {
return "binary(16)";
}
if (type == ObjectId.class) {
return "binary(12)";
}
if (type == Long.class || type == long.class) {
return "bigint";
}
if (type == Integer.class || type == int.class) {
return "int";
}
if (type == Boolean.class || type == boolean.class) {
return "tinyint(1)";
}
if (type == Float.class || type == float.class) {
return "float";
}
if (type == Double.class || type == double.class) {
return "double";
}
if (type == Instant.class) {
return "varchar(33)";
}
if (type == Date.class || type == Timestamp.class) {
return "timestamp(3)";
}
if (type == LocalDate.class) {
return "date";
}
if (type == LocalTime.class) {
return "time";
}
if (type == String.class) {
return "text";
}
if (type == JsonValue.class) {
return "json";
}
if (type.isEnum()) {
final Object[] arr = type.getEnumConstants();
final StringBuilder out = new StringBuilder();
out.append("ENUM(");
boolean first = true;
for (final Object elem : arr) {
if (!first) {
out.append(",");
}
first = false;
out.append("'");
out.append(elem.toString());
out.append("'");
}
out.append(")");
return out.toString();
}
} else if ("sqlite".equals(typelocal)) {
if (type == UUID.class) {
return "BINARY(16)";
}
if (type == ObjectId.class) {
return "BINARY(12)";
}
if (type == Long.class || type == long.class) {
return "INTEGER";
}
if (type == Integer.class || type == int.class) {
return "INTEGER";
}
if (type == Boolean.class || type == boolean.class) {
return "INTEGER";
}
if (type == Float.class || type == float.class) {
return "REAL";
}
if (type == Double.class || type == double.class) {
return "REAL";
}
if (type == Instant.class) {
return "text";
}
if (type == Date.class || type == Timestamp.class) {
return "DATETIME";
}
if (type == LocalDate.class) {
return "DATE";
}
if (type == LocalTime.class) {
return "TIME";
}
if (type == String.class) {
return "text";
}
if (type == JsonValue.class) {
return "text";
}
if (type.isEnum()) {
final Object[] arr = type.getEnumConstants();
final StringBuilder out = new StringBuilder();
out.append("TEXT CHECK(");
out.append(fieldName);
out.append(" IN (");
boolean first = true;
for (final Object elem : arr) {
if (!first) {
out.append(",");
}
first = false;
out.append("'");
out.append(elem.toString());
out.append("'");
}
out.append(" ) )");
return out.toString();
}
} else if ("mongo".equals(typelocal)) {
// no importance for mango ...
return "text";
}
throw new DataAccessException("Imcompatible type of element in object for: " + type.getCanonicalName());
}
public static void createTablesSpecificType(
final String tableName,
final Field primaryField,
final Field elem,
final StringBuilder mainTableBuilder,
final List<String> preOtherTables,
final List<String> postOtherTables,
final boolean createIfNotExist,
final boolean createDrop,
final int fieldId,
final Class<?> classModel,
final QueryOptions options) throws Exception {
final String name = AnnotationTools.getFieldName(elem, options).inTable();
final int limitSize = AnnotationTools.getLimitSize(elem);
final boolean notNull = AnnotationTools.getColumnNotNull(elem);
final boolean primaryKey = AnnotationTools.isPrimaryKey(elem);
final GenerationType strategy = AnnotationTools.getStrategy(elem);
final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0;
final boolean updateTime = elem.getDeclaredAnnotationsByType(UpdateTimestamp.class).length != 0;
final String comment = AnnotationTools.getSchemaDescription(elem);
final String defaultValue = AnnotationTools.getDefault(elem);
if (mainTableBuilder.toString().length() == 0) {
mainTableBuilder.append("\n\t\t`");
} else {
mainTableBuilder.append(",\n\t\t`");
}
mainTableBuilder.append(name);
mainTableBuilder.append("` ");
String typeValue = null;
typeValue = convertTypeInSQL(classModel, name);
if ("text".equals(typeValue) && !"sqlite".equals(ConfigBaseVariable.getDBType())) {
if (limitSize > 0) {
mainTableBuilder.append("varchar(");
mainTableBuilder.append(limitSize);
mainTableBuilder.append(")");
} else {
mainTableBuilder.append("text");
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append(" CHARACTER SET utf8");
}
}
} else {
mainTableBuilder.append(typeValue);
}
mainTableBuilder.append(" ");
if (notNull) {
if (!primaryKey || !"sqlite".equalsIgnoreCase(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("NOT NULL ");
}
if (defaultValue == null) {
if (updateTime || createTime) {
if ("varchar(33)".equals(typeValue)) {
mainTableBuilder.append("DEFAULT DATE_FORMAT(now(6), '%Y-%m-%dT%H:%m:%s.%fZ')");
} else {
mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP");
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("(3)");
}
}
mainTableBuilder.append(" ");
}
if (updateTime) {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
if ("varchar(33)".equals(typeValue)) {
mainTableBuilder.append("ON UPDATE DATE_FORMAT(now(6), '%Y-%m-%dT%H:%m:%s.%fZ')");
} else {
mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP");
mainTableBuilder.append("(3)");
}
} else {
// TODO: add trigger:
/* CREATE TRIGGER your_table_trig AFTER UPDATE ON your_table BEGIN update your_table SET updated_on = datetime('now') WHERE user_id = NEW.user_id; END; */
final StringBuilder triggerBuilder = new StringBuilder();
triggerBuilder.append("CREATE TRIGGER ");
triggerBuilder.append(tableName);
triggerBuilder.append("_update_trigger AFTER UPDATE ON ");
triggerBuilder.append(tableName);
triggerBuilder.append(" \nBEGIN \n update ");
triggerBuilder.append(tableName);
triggerBuilder.append(" SET ");
triggerBuilder.append(name);
// triggerBuilder.append(" = datetime('now') WHERE id = NEW.id; \n");
final String tablePrimaryKey = primaryField.getName();
if ("varchar(33)".equals(typeValue)) {
triggerBuilder.append(" = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE " + tablePrimaryKey
+ " = NEW." + tablePrimaryKey + "; \n");
} else {
triggerBuilder.append(" = strftime('%Y-%m-%d %H:%M:%f', 'now') WHERE " + tablePrimaryKey
+ " = NEW." + tablePrimaryKey + "; \n");
}
triggerBuilder.append("END;");
postOtherTables.add(triggerBuilder.toString());
}
mainTableBuilder.append(" ");
}
} else {
mainTableBuilder.append("DEFAULT ");
if ("CURRENT_TIMESTAMP(3)".equals(defaultValue) && "sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("CURRENT_TIMESTAMP");
} else {
mainTableBuilder.append(defaultValue);
}
mainTableBuilder.append(" ");
if (updateTime) {
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("ON UPDATE CURRENT_TIMESTAMP");
mainTableBuilder.append("(3)");
}
mainTableBuilder.append(" ");
}
}
} else if (defaultValue == null) {
if (updateTime || createTime) {
if ("sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP ");
} else {
mainTableBuilder.append("DEFAULT CURRENT_TIMESTAMP(3) ");
}
} else if (primaryKey) {
mainTableBuilder.append("NOT NULL ");
} else {
mainTableBuilder.append("DEFAULT NULL ");
}
} else {
mainTableBuilder.append("DEFAULT ");
mainTableBuilder.append(defaultValue);
mainTableBuilder.append(" ");
}
if (primaryKey && "sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("PRIMARY KEY ");
}
if (strategy == GenerationType.IDENTITY) {
if ("binary(16)".equals(typeValue)) {
} else if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("AUTO_INCREMENT ");
} else {
mainTableBuilder.append("AUTOINCREMENT ");
}
} else if (strategy != null) {
throw new DataAccessException("Can not generate a stategy different of IDENTITY");
}
if (comment != null && !"sqlite".equals(ConfigBaseVariable.getDBType())) {
mainTableBuilder.append("COMMENT '");
mainTableBuilder.append(comment.replace('\'', '\''));
mainTableBuilder.append("' ");
}
}
private static boolean isFieldFromSuperClass(
final Class<?> model,
final String filedName,
final QueryOptions options) {
final Class<?> superClass = model.getSuperclass();
if (superClass == null) {
return false;
}
for (final Field field : superClass.getFields()) {
String name;
try {
name = AnnotationTools.getFieldName(field, options).inTable();
if (filedName.equals(name)) {
return true;
}
} catch (final Exception e) {
// TODO Auto-generated catch block
LOGGER.trace("Catch error field name in parent create data table: {}", e.getMessage());
}
}
return false;
}
public static List<String> createTable(final Class<?> clazz) throws Exception {
return createTable(clazz, null);
}
public static List<String> createTable(final Class<?> clazz, final QueryOptions options) throws Exception {
final String tableName = AnnotationTools.getTableName(clazz, options);
boolean createDrop = false;
if (options != null) {
createDrop = options.exist(CreateDropTable.class);
}
final boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(DataIfNotExists.class).length != 0;
final List<String> preActionList = new ArrayList<>();
final List<String> postActionList = new ArrayList<>();
final StringBuilder out = new StringBuilder();
// Drop Table
if (createIfNotExist && createDrop) {
final StringBuilder tableTmp = new StringBuilder();
tableTmp.append("DROP TABLE IF EXISTS `");
tableTmp.append(tableName);
tableTmp.append("`;");
postActionList.add(tableTmp.toString());
}
// create Table:
out.append("CREATE TABLE `");
out.append(tableName);
out.append("` (");
int fieldId = 0;
LOGGER.debug("===> TABLE `{}`", tableName);
final List<String> primaryKeys = new ArrayList<>();
final Field primaryField = AnnotationTools.getPrimaryKeyField(clazz);
for (final Field elem : clazz.getFields()) {
// DEtect the primary key (support only one primary key right now...
if (AnnotationTools.isPrimaryKey(elem)) {
primaryKeys.add(AnnotationTools.getFieldName(elem, options).inTable());
}
}
// Here we insert the data in the reverse mode ==> the parent class add there parameter at the start (we reorder the field with the parenting).
StringBuilder tmpOut = new StringBuilder();
StringBuilder reverseOut = new StringBuilder();
final List<String> alreadyAdded = new ArrayList<>();
Class<?> currentClazz = clazz;
final Field tablePrimaryKeyField = AnnotationTools.getPrimaryKeyField(clazz);
while (currentClazz != null) {
fieldId = 0;
LOGGER.trace("parse class: '{}'", currentClazz.getCanonicalName());
for (final Field elem : clazz.getFields()) {
// static field is only for internal global declaration ==> remove it ..
if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) {
continue;
}
final String dataName = AnnotationTools.getFieldName(elem, options).inTable();
if (isFieldFromSuperClass(currentClazz, dataName, options)) {
LOGGER.trace(" SKIP: '{}'", elem.getName());
continue;
}
if (alreadyAdded.contains(dataName)) {
LOGGER.trace(" SKIP2: '{}'", elem.getName());
continue;
}
alreadyAdded.add(dataName);
List<OptionSpecifyType> specificTypes = new ArrayList<>();
if (options != null) {
specificTypes = options.get(OptionSpecifyType.class);
}
Class<?> basicType = elem.getType();
if (basicType == Object.class) {
for (final OptionSpecifyType specify : specificTypes) {
if (specify.name.equals(elem.getName())) {
basicType = specify.clazz;
LOGGER.trace("Detect overwrite of typing ... '{}' => '{}'",
elem.getType().getCanonicalName(), specify.clazz.getCanonicalName());
break;
}
}
}
LOGGER.trace(" + '{}'", elem.getName());
if (DBAccessSQL.isAddOnField(elem)) {
final DataAccessAddOn addOn = DBAccessSQL.findAddOnforField(elem);
LOGGER.trace("Create type for: {} ==> {} (ADD-ON)",
AnnotationTools.getFieldName(elem, options).inTable(), basicType);
if (addOn != null) {
addOn.createTables(tableName, primaryField, elem, tmpOut, preActionList, postActionList,
createIfNotExist, createDrop, fieldId, options);
} else {
throw new DataAccessException("Element matked as add-on but add-on does not loaded: table:"
+ tableName + " field name=" + AnnotationTools.getFieldName(elem, options).inTable()
+ " type=" + basicType);
}
} else {
LOGGER.trace("Create type for: {} ==> {}", AnnotationTools.getFieldName(elem, options).inTable(),
basicType);
DataFactory.createTablesSpecificType(tableName, tablePrimaryKeyField, elem, tmpOut, preActionList,
postActionList, createIfNotExist, createDrop, fieldId, basicType, options);
}
fieldId++;
}
final boolean dataInThisObject = tmpOut.toString().length() > 0;
if (dataInThisObject) {
LOGGER.info("Previous Object : '{}'", reverseOut.toString());
final boolean dataInPreviousObject = reverseOut.toString().length() > 0;
if (dataInPreviousObject) {
tmpOut.append(", ");
tmpOut.append(reverseOut.toString());
}
reverseOut = tmpOut;
tmpOut = new StringBuilder();
}
currentClazz = currentClazz.getSuperclass();
if (currentClazz == Object.class) {
break;
}
}
out.append(reverseOut.toString());
if (primaryKeys.size() != 0 && !"sqlite".equals(ConfigBaseVariable.getDBType())) {
out.append(",\n\tPRIMARY KEY (`");
for (int iii = 0; iii < primaryKeys.size(); iii++) {
if (iii != 0) {
out.append(",");
}
out.append(primaryKeys.get(iii));
}
out.append("`)");
}
out.append("\n\t)");
if (!"sqlite".equals(ConfigBaseVariable.getDBType())) {
out.append(" ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci");
}
out.append(";");
preActionList.add(out.toString());
preActionList.addAll(postActionList);
return preActionList;
}
}

View File

@ -1,18 +0,0 @@
package org.kar.archidata.dataAccess;
// Mark as deprecated while the concept is not ready ...
@Deprecated
public class Foreign<T> {
public final Long id;
public final T data;
public Foreign(final Long id) {
this.id = id;
this.data = null;
}
public Foreign(final T data) {
this.id = null;
this.data = data;
}
}

View File

@ -1,5 +0,0 @@
package org.kar.archidata.dataAccess;
public interface LazyGetter {
void doRequest() throws Exception;
}

View File

@ -1,66 +0,0 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryAnd implements QueryItem {
protected final List<QueryItem> childs;
public QueryAnd(final List<QueryItem> child) {
this.childs = child;
}
public QueryAnd(final QueryItem... child) {
this.childs = new ArrayList<>();
Collections.addAll(this.childs, child);
}
public void add(final QueryItem... child) {
Collections.addAll(this.childs, child);
}
@Override
public void generateQuery(final StringBuilder query, final String tableName) {
if (this.childs.size() >= 1) {
query.append(" (");
}
boolean first = true;
for (final QueryItem elem : this.childs) {
if (first) {
first = false;
} else {
query.append(" AND ");
}
elem.generateQuery(query, tableName);
}
if (this.childs.size() >= 1) {
query.append(")");
}
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final QueryItem elem : this.childs) {
elem.injectQuery(ioDb, ps, iii);
}
}
public int size() {
return this.childs.size();
}
@Override
public void generateFilter(final List<Bson> filters) {
final List<Bson> filtersLocal = new ArrayList<>();
for (final QueryItem elem : this.childs) {
elem.generateFilter(filtersLocal);
}
filters.add(Filters.and(filtersLocal.toArray(new Bson[0])));
}
}

View File

@ -1,67 +0,0 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.client.model.Filters;
public class QueryCondition implements QueryItem {
static final Logger LOGGER = LoggerFactory.getLogger(DBAccess.class);
private final String key;
private final String comparator;
private final Object value;
/**
* Simple DB comparison element. Note the injected object is injected in the statement and not in the query directly.
* @param key Field to check (the Model property name)
* @param comparator (simple comparator String)
* @param value Value that the field must be equals.
*/
public QueryCondition(final String key, final String comparator, final Object value) {
this.key = key;
this.comparator = comparator;
this.value = value;
}
@Override
public void generateQuery(final StringBuilder query, final String tableName) {
if (tableName != null) {
query.append(tableName);
query.append(".");
}
query.append(this.key);
query.append(" ");
query.append(this.comparator);
query.append(" ?");
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
ioDb.addElement(ps, this.value, iii);
iii.inc();
}
@Override
public void generateFilter(final List<Bson> filters) {
if ("=".equals(this.comparator)) {
filters.add(Filters.eq(this.key, this.value));
} else if ("!=".equals(this.comparator)) {
filters.add(Filters.ne(this.key, this.value));
} else if (">".equals(this.comparator)) {
filters.add(Filters.gt(this.key, this.value));
} else if (">=".equals(this.comparator)) {
filters.add(Filters.gte(this.key, this.value));
} else if ("<".equals(this.comparator)) {
filters.add(Filters.lt(this.key, this.value));
} else if ("<=".equals(this.comparator)) {
filters.add(Filters.lte(this.key, this.value));
} else {
LOGGER.error("Not manage comparison: '{}'", this.key);
}
}
}

View File

@ -1,62 +0,0 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryInList<T> implements QueryItem {
protected final String key;
protected final String comparator;
protected final List<T> value;
protected QueryInList(final String key, final String comparator, final List<T> value) {
this.key = key;
this.comparator = comparator;
this.value = value;
}
public QueryInList(final String key, final List<T> value) {
this(key, "IN", value);
}
public QueryInList(final String key, final T... value) {
this(key, "IN", List.of(value));
}
@Override
public void generateQuery(final StringBuilder query, final String tableName) {
if (tableName != null) {
query.append(tableName);
query.append(".");
}
query.append(this.key);
query.append(" ");
query.append(this.comparator);
query.append(" (");
for (int iii = 0; iii < this.value.size(); iii++) {
if (iii != 0) {
query.append(",?");
} else {
query.append("?");
}
}
query.append(")");
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final Object elem : this.value) {
ioDb.addElement(ps, elem, iii);
iii.inc();
}
}
@Override
public void generateFilter(final List<Bson> filters) {
filters.add(Filters.in(this.key, this.value));
}
}

View File

@ -1,17 +0,0 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
public interface QueryItem {
// For SQL mode query construction
void generateQuery(StringBuilder query, String tableName);
// For SQL mode query injection
void injectQuery(DBAccessSQL ioDb, PreparedStatement ps, CountInOut iii) throws Exception;
// For No-SQL mode filter creation
void generateFilter(List<Bson> filters);
}

View File

@ -1,9 +0,0 @@
package org.kar.archidata.dataAccess;
import java.util.List;
public class QueryNoInList<T> extends QueryInList<T> {
public QueryNoInList(final String key, final List<T> value) {
super(key, "NOT IN", value);
}
}

View File

@ -1,35 +0,0 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryNotNull implements QueryItem {
private final String key;
public QueryNotNull(final String key) {
this.key = key;
}
@Override
public void generateQuery(final StringBuilder query, final String tableName) {
if (tableName != null) {
query.append(tableName);
query.append(".");
}
query.append(this.key);
query.append(" IS NOT NULL");
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii)
throws Exception {}
@Override
public void generateFilter(final List<Bson> filters) {
filters.add(Filters.exists(this.key));
}
}

View File

@ -1,36 +0,0 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryNull implements QueryItem {
private final String key;
public QueryNull(final String key) {
this.key = key;
}
@Override
public void generateQuery(final StringBuilder query, final String tableName) {
if (tableName != null) {
query.append(tableName);
query.append(".");
}
query.append(this.key);
query.append(" IS NULL");
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii)
throws Exception {}
@Override
public void generateFilter(final List<Bson> filters) {
// Not sure of the result ... maybe check it ...
filters.add(Filters.eq(this.key, null));
}
}

View File

@ -1,74 +0,0 @@
package org.kar.archidata.dataAccess;
import java.util.ArrayList;
import java.util.List;
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
import org.kar.archidata.dataAccess.options.CreateDropTable;
import org.kar.archidata.dataAccess.options.QueryOption;
import org.kar.archidata.dataAccess.options.ReadAllColumn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class QueryOptions {
static final Logger LOGGER = LoggerFactory.getLogger(QueryOptions.class);
public static final ReadAllColumn READ_ALL_COLOMN = new ReadAllColumn();
public static final AccessDeletedItems ACCESS_DELETED_ITEMS = new AccessDeletedItems();
public static final CreateDropTable CREATE_DROP_TABLE = new CreateDropTable();
private final List<QueryOption> options = new ArrayList<>();
public QueryOptions() {}
public QueryOptions(final QueryOption... elems) {
if (elems == null || elems.length == 0) {
return;
}
for (final QueryOption elem : elems) {
add(elem);
}
}
public void add(final QueryOption option) {
if (option == null) {
return;
}
this.options.add(option);
}
public List<QueryOption> getAll() {
return this.options;
}
public QueryOption[] getAllArray() {
return this.options.toArray(new QueryOption[0]);
}
@SuppressWarnings("unchecked")
public <T> List<T> get(final Class<T> type) {
final List<T> out = new ArrayList<>();
for (final QueryOption elem : this.options) {
if (elem.getClass() == type) {
out.add((T) elem);
}
}
return out;
}
public boolean exist(final Class<?> type) {
for (final QueryOption elem : this.options) {
if (elem.getClass() == type) {
return true;
}
}
return false;
}
public static boolean readAllColomn(final QueryOptions options) {
if (options != null) {
return options.exist(ReadAllColumn.class);
}
return false;
}
}

View File

@ -1,56 +0,0 @@
package org.kar.archidata.dataAccess;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import org.bson.conversions.Bson;
import com.mongodb.client.model.Filters;
public class QueryOr implements QueryItem {
protected final List<QueryItem> childs;
public QueryOr(final List<QueryItem> childs) {
this.childs = childs;
}
public QueryOr(final QueryItem... childs) {
this.childs = List.of(childs);
}
@Override
public void generateQuery(final StringBuilder query, final String tableName) {
if (this.childs.size() >= 1) {
query.append(" (");
}
boolean first = true;
for (final QueryItem elem : this.childs) {
if (first) {
first = false;
} else {
query.append(" OR ");
}
elem.generateQuery(query, tableName);
}
if (this.childs.size() >= 1) {
query.append(")");
}
}
@Override
public void injectQuery(final DBAccessSQL ioDb, final PreparedStatement ps, final CountInOut iii) throws Exception {
for (final QueryItem elem : this.childs) {
elem.injectQuery(ioDb, ps, iii);
}
}
@Override
public void generateFilter(final List<Bson> filters) {
final List<Bson> filtersLocal = new ArrayList<>();
for (final QueryItem elem : this.childs) {
elem.generateFilter(filtersLocal);
}
filters.add(Filters.or(filtersLocal.toArray(new Bson[0])));
}
}

View File

@ -1,7 +0,0 @@
package org.kar.archidata.dataAccess;
import java.sql.ResultSet;
public interface RetreiveFromDB {
void doRequest(final ResultSet rs, Object obj) throws Exception;
}

Some files were not shown because too many files have changed in this diff Show More