diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a64b98a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/.gradle/6.7/fileChanges/last-build.bin b/.gradle/6.7/fileChanges/last-build.bin
new file mode 100644
index 0000000..f76dd23
Binary files /dev/null and b/.gradle/6.7/fileChanges/last-build.bin differ
diff --git a/.gradle/6.7/fileHashes/fileHashes.lock b/.gradle/6.7/fileHashes/fileHashes.lock
new file mode 100644
index 0000000..f626512
Binary files /dev/null and b/.gradle/6.7/fileHashes/fileHashes.lock differ
diff --git a/.gradle/6.7/gc.properties b/.gradle/6.7/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 0000000..b26f01b
Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 0000000..aef6247
--- /dev/null
+++ b/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Fri Apr 02 11:16:16 CST 2021
+gradle.version=6.7
diff --git a/.gradle/checksums/checksums.lock b/.gradle/checksums/checksums.lock
new file mode 100644
index 0000000..77a9380
Binary files /dev/null and b/.gradle/checksums/checksums.lock differ
diff --git a/.gradle/configuration-cache/gc.properties b/.gradle/configuration-cache/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..73f69e0
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..a19e09f
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+ATTCK
\ No newline at end of file
diff --git a/.idea/GraphDatabaseSupport_DataSourcesState.xml b/.idea/GraphDatabaseSupport_DataSourcesState.xml
new file mode 100644
index 0000000..10e6c94
--- /dev/null
+++ b/.idea/GraphDatabaseSupport_DataSourcesState.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..5d6b0cb
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dictionaries/zhanghanwen.xml b/.idea/dictionaries/zhanghanwen.xml
new file mode 100644
index 0000000..681bf3f
--- /dev/null
+++ b/.idea/dictionaries/zhanghanwen.xml
@@ -0,0 +1,15 @@
+
+
+
+ alimaven
+ aliyun
+ attck
+ capec
+ spearphishing
+ stix
+ tful
+ uestc
+ zhanghanwen
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..63e9001
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..07f513a
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..990dc9d
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml b/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml
new file mode 100644
index 0000000..6fec8f4
--- /dev/null
+++ b/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml b/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml
new file mode 100644
index 0000000..9eb8596
--- /dev/null
+++ b/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__com_alibaba_fastjson_1_2_75.xml b/.idea/libraries/Maven__com_alibaba_fastjson_1_2_75.xml
new file mode 100644
index 0000000..3c0095e
--- /dev/null
+++ b/.idea/libraries/Maven__com_alibaba_fastjson_1_2_75.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_11_4.xml b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_11_4.xml
new file mode 100644
index 0000000..b269864
--- /dev/null
+++ b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_11_4.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_11_4.xml b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_11_4.xml
new file mode 100644
index 0000000..ffff0a6
--- /dev/null
+++ b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_11_4.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_11_4.xml b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_11_4.xml
new file mode 100644
index 0000000..98292c5
--- /dev/null
+++ b/.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_11_4.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_11_4.xml b/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_11_4.xml
new file mode 100644
index 0000000..5e7e738
--- /dev/null
+++ b/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_11_4.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_11_4.xml b/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_11_4.xml
new file mode 100644
index 0000000..acb88ad
--- /dev/null
+++ b/.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_11_4.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_11_4.xml b/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_11_4.xml
new file mode 100644
index 0000000..8c681f4
--- /dev/null
+++ b/.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_11_4.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_4_0.xml b/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_4_0.xml
new file mode 100644
index 0000000..f19f6eb
--- /dev/null
+++ b/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_4_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml b/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml
new file mode 100644
index 0000000..b8581a6
--- /dev/null
+++ b/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__commons_codec_commons_codec_1_14.xml b/.idea/libraries/Maven__commons_codec_commons_codec_1_14.xml
new file mode 100644
index 0000000..50b8f2b
--- /dev/null
+++ b/.idea/libraries/Maven__commons_codec_commons_codec_1_14.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__io_github_classgraph_classgraph_4_8_86.xml b/.idea/libraries/Maven__io_github_classgraph_classgraph_4_8_86.xml
new file mode 100644
index 0000000..8b928f7
--- /dev/null
+++ b/.idea/libraries/Maven__io_github_classgraph_classgraph_4_8_86.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml b/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml
new file mode 100644
index 0000000..be90656
--- /dev/null
+++ b/.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml b/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml
new file mode 100644
index 0000000..cba9dd2
--- /dev/null
+++ b/.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml b/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml
new file mode 100644
index 0000000..04213f7
--- /dev/null
+++ b/.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__junit_junit_4_13_2.xml b/.idea/libraries/Maven__junit_junit_4_13_2.xml
new file mode 100644
index 0000000..0a760c8
--- /dev/null
+++ b/.idea/libraries/Maven__junit_junit_4_13_2.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_10_20.xml b/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_10_20.xml
new file mode 100644
index 0000000..e4da145
--- /dev/null
+++ b/.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_10_20.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_10_20.xml b/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_10_20.xml
new file mode 100644
index 0000000..ce60b61
--- /dev/null
+++ b/.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_10_20.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__net_minidev_accessors_smart_1_2.xml b/.idea/libraries/Maven__net_minidev_accessors_smart_1_2.xml
new file mode 100644
index 0000000..b3d3858
--- /dev/null
+++ b/.idea/libraries/Maven__net_minidev_accessors_smart_1_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__net_minidev_json_smart_2_3.xml b/.idea/libraries/Maven__net_minidev_json_smart_2_3.xml
new file mode 100644
index 0000000..1083023
--- /dev/null
+++ b/.idea/libraries/Maven__net_minidev_json_smart_2_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_10.xml b/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_10.xml
new file mode 100644
index 0000000..00de553
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_10.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_13.xml b/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_13.xml
new file mode 100644
index 0000000..63bee0e
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_13.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_14.xml b/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_14.xml
new file mode 100644
index 0000000..427f319
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_14.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_13_3.xml b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_13_3.xml
new file mode 100644
index 0000000..8ad4996
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_13_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_13_3.xml b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_13_3.xml
new file mode 100644
index 0000000..57e6ac4
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_13_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_43.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_43.xml
new file mode 100644
index 0000000..40e23f0
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_43.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_43.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_43.xml
new file mode 100644
index 0000000..d71ef01
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_43.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml b/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml
new file mode 100644
index 0000000..f854ab0
--- /dev/null
+++ b/.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_assertj_assertj_core_3_16_1.xml b/.idea/libraries/Maven__org_assertj_assertj_core_3_16_1.xml
new file mode 100644
index 0000000..8976500
--- /dev/null
+++ b/.idea/libraries/Maven__org_assertj_assertj_core_3_16_1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_glassfish_jakarta_el_3_0_3.xml b/.idea/libraries/Maven__org_glassfish_jakarta_el_3_0_3.xml
new file mode 100644
index 0000000..ae5020d
--- /dev/null
+++ b/.idea/libraries/Maven__org_glassfish_jakarta_el_3_0_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml b/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml
new file mode 100644
index 0000000..6b5496f
--- /dev/null
+++ b/.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_jetbrains_annotations_20_1_0.xml b/.idea/libraries/Maven__org_jetbrains_annotations_20_1_0.xml
new file mode 100644
index 0000000..de125e3
--- /dev/null
+++ b/.idea/libraries/Maven__org_jetbrains_annotations_20_1_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_8_0_M1.xml b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_8_0_M1.xml
new file mode 100644
index 0000000..f0982aa
--- /dev/null
+++ b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_8_0_M1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_6_3.xml b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_6_3.xml
new file mode 100644
index 0000000..3f50def
--- /dev/null
+++ b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_6_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_6_3.xml b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_6_3.xml
new file mode 100644
index 0000000..2331281
--- /dev/null
+++ b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_6_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_6_3.xml b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_6_3.xml
new file mode 100644
index 0000000..98e9d9e
--- /dev/null
+++ b/.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_6_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_6_3.xml b/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_6_3.xml
new file mode 100644
index 0000000..0122027
--- /dev/null
+++ b/.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_6_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_6_3.xml b/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_6_3.xml
new file mode 100644
index 0000000..8ddd1f8
--- /dev/null
+++ b/.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_6_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_junit_vintage_junit_vintage_engine_5_6_3.xml b/.idea/libraries/Maven__org_junit_vintage_junit_vintage_engine_5_6_3.xml
new file mode 100644
index 0000000..65905f0
--- /dev/null
+++ b/.idea/libraries/Maven__org_junit_vintage_junit_vintage_engine_5_6_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_mockito_mockito_core_3_3_3.xml b/.idea/libraries/Maven__org_mockito_mockito_core_3_3_3.xml
new file mode 100644
index 0000000..d2f4afa
--- /dev/null
+++ b/.idea/libraries/Maven__org_mockito_mockito_core_3_3_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_3_3_3.xml b/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_3_3_3.xml
new file mode 100644
index 0000000..6c02a63
--- /dev/null
+++ b/.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_3_3_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_neo4j_driver_neo4j_java_driver_4_0_2.xml b/.idea/libraries/Maven__org_neo4j_driver_neo4j_java_driver_4_0_2.xml
new file mode 100644
index 0000000..3d4d1a3
--- /dev/null
+++ b/.idea/libraries/Maven__org_neo4j_driver_neo4j_java_driver_4_0_2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_neo4j_neo4j_ogm_api_3_2_20.xml b/.idea/libraries/Maven__org_neo4j_neo4j_ogm_api_3_2_20.xml
new file mode 100644
index 0000000..73b9041
--- /dev/null
+++ b/.idea/libraries/Maven__org_neo4j_neo4j_ogm_api_3_2_20.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_neo4j_neo4j_ogm_bolt_driver_3_2_20.xml b/.idea/libraries/Maven__org_neo4j_neo4j_ogm_bolt_driver_3_2_20.xml
new file mode 100644
index 0000000..173d00c
--- /dev/null
+++ b/.idea/libraries/Maven__org_neo4j_neo4j_ogm_bolt_driver_3_2_20.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_neo4j_neo4j_ogm_core_3_2_21.xml b/.idea/libraries/Maven__org_neo4j_neo4j_ogm_core_3_2_21.xml
new file mode 100644
index 0000000..85ea97f
--- /dev/null
+++ b/.idea/libraries/Maven__org_neo4j_neo4j_ogm_core_3_2_21.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_neo4j_neo4j_ogm_http_driver_3_2_21.xml b/.idea/libraries/Maven__org_neo4j_neo4j_ogm_http_driver_3_2_21.xml
new file mode 100644
index 0000000..d3974bb
--- /dev/null
+++ b/.idea/libraries/Maven__org_neo4j_neo4j_ogm_http_driver_3_2_21.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_objenesis_objenesis_2_6.xml b/.idea/libraries/Maven__org_objenesis_objenesis_2_6.xml
new file mode 100644
index 0000000..af41e3b
--- /dev/null
+++ b/.idea/libraries/Maven__org_objenesis_objenesis_2_6.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml b/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml
new file mode 100644
index 0000000..fbc1b16
--- /dev/null
+++ b/.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_ow2_asm_asm_5_0_4.xml b/.idea/libraries/Maven__org_ow2_asm_asm_5_0_4.xml
new file mode 100644
index 0000000..0bf8cf2
--- /dev/null
+++ b/.idea/libraries/Maven__org_ow2_asm_asm_5_0_4.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_projectlombok_lombok_1_18_18.xml b/.idea/libraries/Maven__org_projectlombok_lombok_1_18_18.xml
new file mode 100644
index 0000000..9c76b55
--- /dev/null
+++ b/.idea/libraries/Maven__org_projectlombok_lombok_1_18_18.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_reactivestreams_reactive_streams_1_0_3.xml b/.idea/libraries/Maven__org_reactivestreams_reactive_streams_1_0_3.xml
new file mode 100644
index 0000000..f17253b
--- /dev/null
+++ b/.idea/libraries/Maven__org_reactivestreams_reactive_streams_1_0_3.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_0.xml b/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_0.xml
new file mode 100644
index 0000000..c4c54d6
--- /dev/null
+++ b/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_30.xml b/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_30.xml
new file mode 100644
index 0000000..27229ce
--- /dev/null
+++ b/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_30.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_30.xml b/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_30.xml
new file mode 100644
index 0000000..02b6812
--- /dev/null
+++ b/.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_30.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..50e8ddb
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..9efa19e
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..3f1f015
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..2fb0cfc
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..06d24a0
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..9071107
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..5dc2519
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..10d85d1
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..227a483
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_3_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_3_9_RELEASE.xml
new file mode 100644
index 0000000..2de0c26
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_3_9_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_data_spring_data_commons_2_3_7_RELEASE.xml b/.idea/libraries/Maven__org_springframework_data_spring_data_commons_2_3_7_RELEASE.xml
new file mode 100644
index 0000000..db7d0ce
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_data_spring_data_commons_2_3_7_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_data_spring_data_neo4j_5_3_7_RELEASE.xml b/.idea/libraries/Maven__org_springframework_data_spring_data_neo4j_5_3_7_RELEASE.xml
new file mode 100644
index 0000000..c39adf3
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_data_spring_data_neo4j_5_3_7_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_aop_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_aop_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..774b937
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_aop_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_beans_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_beans_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..a48dfbd
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_beans_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_context_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_context_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..71b6163
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_context_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_core_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_core_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..ea74386
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_core_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_expression_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_expression_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..51ef5c5
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_expression_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_jcl_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_jcl_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..fa347dc
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_jcl_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_test_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_test_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..8503980
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_test_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_tx_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_tx_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..8758aab
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_tx_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_web_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_web_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..485f518
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_web_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_spring_webmvc_5_2_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_webmvc_5_2_13_RELEASE.xml
new file mode 100644
index 0000000..cec781f
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_spring_webmvc_5_2_13_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_7_0.xml b/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_7_0.xml
new file mode 100644
index 0000000..006a8d3
--- /dev/null
+++ b/.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_7_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_yaml_snakeyaml_1_26.xml b/.idea/libraries/Maven__org_yaml_snakeyaml_1_26.xml
new file mode 100644
index 0000000..e998675
--- /dev/null
+++ b/.idea/libraries/Maven__org_yaml_snakeyaml_1_26.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..f70af36
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..a2975ee
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..e76d1f3
--- /dev/null
+++ b/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+ private static final String WRAPPER_VERSION = "0.5.6";
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+ * use instead of the default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+ ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH =
+ ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main(String args[]) {
+ System.out.println("- Downloader started");
+ File baseDirectory = new File(args[0]);
+ System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+ String url = DEFAULT_DOWNLOAD_URL;
+ if(mavenWrapperPropertyFile.exists()) {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try {
+ mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+ url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+ } catch (IOException e) {
+ System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+ } finally {
+ try {
+ if(mavenWrapperPropertyFileInputStream != null) {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println("- Downloading from: " + url);
+
+ File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+ if(!outputFile.getParentFile().exists()) {
+ if(!outputFile.getParentFile().mkdirs()) {
+ System.out.println(
+ "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+ }
+ }
+ System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+ try {
+ downloadFileFromURL(url, outputFile);
+ System.out.println("Done");
+ System.exit(0);
+ } catch (Throwable e) {
+ System.out.println("- Error downloading");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+ if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+ String username = System.getenv("MVNW_USERNAME");
+ char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+ Authenticator.setDefault(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(username, password);
+ }
+ });
+ }
+ URL website = new URL(urlString);
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel(website.openStream());
+ FileOutputStream fos = new FileOutputStream(destination);
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ fos.close();
+ rbc.close();
+ }
+
+}
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..2cc7d4a
Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..642d572
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
diff --git a/ATTCK.iml b/ATTCK.iml
new file mode 100644
index 0000000..c27066b
--- /dev/null
+++ b/ATTCK.iml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d5c4d0b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,200 @@
+#ATT&CK知识图谱增删改查后端开发文档
+
+### 本项目是ATT&CK攻防知识图谱数据库的增删改查后端接口,知识图谱存储于neo4j数据库中。
+
+##1. 开发基本信息
+本项目采用`Java 11`作为开发语言,使用`SpringBoot`作为后端基本框架,使用`Spring Data neo4j`作为数据库层。
+此框架具有轻量、开发便捷、耦合度低等特点。
+
+* JDK版本:`OpenJDK 11.0.10`
+* 项目构建:`Apache Maven 3.8.1`
+* 版本控制:`git 2.31.1`
+* 开发环境:`macOS 11.2.3`
+* 测试环境:`Ubuntu Linux 20.04 LTS`
+* 使用IDE:`JetBrains Intellij IDEA Ultimate 2021.1`
+
+## 2. 项目概况
+
+### i. 关于项目整体情况,详见 [JavaDoc](../JavaDoc/index.html)
+
+### ii. 测试样例
+取自 test/java/uestc/zhanghanwen/ATTCK/RestWebControllers 中的JUnit测试类
+
+### iii. 接口详见 [USAGE.md](USAGE.md)
+
+## 3. 项目UML结构
+
+![](images/ATTCKApplication.png)
+
+### Spring Service 总体情况,`main`方法位于`ATTCKApplication`中,所有`service`通过`@Service`注解自动注册,并通过`@Autowired`注解绑定。
+
+
+
+
+![](images/RetrieveController.png)
+
+### 如图所示,是`RetrieveController`与`ATTCKApplication`的自动绑定
+
+
+
+
+![](images/PackageRetrieveServices.png)
+
+### `RetrieveController`通过调用`Wrappers`包中的`QueryWrapper`, `ResponseWrapper`, `ResultWrapper`类与`RetrieveServices`包交换
+
+
+
+
+
+
+
+![](images/ServiceBundle.png)
+
+### 具体而言,`ServiceBundle`为`RestWebControllers`所调用,为某一类Service的集合
+
+
+
+
+
+![](images/Service.png)
+
+### 为了让不同的`Service`实现不同的方法,都继承自`ServiceInterface`
+
+
+
+
+![](images/ServiceImplement.png)
+
+### 而具体的`***ServiceImpl`继承自`ATTCKService`
+
+
+
+
+![](images/PackagePOJOs.png)
+
+### 数据绑定层与POJO(Plain Old Java Object)
+
+
+
+
+## 4. Official documentations of Spring data Neo4j
+### Getting Started
+
+#### Reference Documentation
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.3.2.RELEASE/maven-plugin/reference/html/)
+* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.3.2.RELEASE/maven-plugin/reference/html/#build-image)
+* [Spring Web](https://docs.spring.io/spring-boot/docs/2.3.2.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications)
+* [Spring Data Neo4j](https://docs.spring.io/spring-boot/docs/2.3.2.RELEASE/reference/htmlsingle/#boot-features-neo4j)
+
+#### Guides
+The following guides illustrate how to use some features concretely:
+
+* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
+* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
+* [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/)
+* [Accessing Data with Neo4j](https://spring.io/guides/gs/accessing-data-neo4j/)
+
+## 5. Official documents of ATT&CK
+
+### cti
+The Cyber Threat Intelligence Repository of ATT&CK and CAPEC catalogs expressed in STIX 2.0 JSON.
+
+### ATT&CK
+ATT&CK is a catalog of techniques and tactics that describe post-compromise adversary behavior on typical enterprise IT environments. The core use cases involve using the catalog to analyze, triage, compare, describe, relate, and share post-compromise adversary behavior.
+
+https://attack.mitre.org
+
+### STIX
+Structured Threat Information Expression (STIX™) is a language and serialization format used to exchange cyber threat intelligence (CTI).
+
+STIX enables organizations to share CTI with one another in a consistent and machine-readable manner, allowing security communities to better understand what computer-based attacks they are most likely to see and to anticipate and/or respond to those attacks faster and more effectively.
+
+STIX is designed to improve many capabilities, such as collaborative threat analysis, automated threat exchange, automated detection and response, and more.
+
+https://oasis-open.github.io/cti-documentation/
+
+### CAPEC
+
+Understanding how the adversary operates is essential to effective cyber-security. CAPEC™ helps by providing a comprehensive dictionary of known patterns of attacks employed by adversaries to exploit known weaknesses in cyber-enabled capabilities. It can be used by analysts, developers, testers, and educators to advance community understanding and enhance defenses.
+
+- Focuses on application security
+- Enumerates exploits against vulnerable systems
+- Includes social engineering / supply chain
+- Associated with Common Weakness Enumeration (CWE)
+
+https://capec.mitre.org/
+
+### Mapping Concepts
+First, we must describe how ATT&CK objects and properties map to STIX 2.0 objects and properties.
+
+#### Objects
+In ATT&CK, there are three main concepts (excluding Tactics for now): Techniques, Groups, and Software. Most techniques also have Mitigations. STIX 2.0 describes these as objects and uses different terminology to describe them. The following table is a mapping of ATT&CK concepts to STIX 2.0 objects:
+
+ATT&CK concept | STIX Object type
+---------------|-----------------
+Technique | `attack-pattern`
+Group | `intrusion-set`
+Software | `malware` or `tool`
+Mitigation | `course-of-action`
+Tactic | `x-mitre-tactic`
+Matrix | `x-mitre-matrix`
+
+The above STIX types are found as literal strings assigned to the `type` property of the STIX JSON object. As shown in the table, in STIX 2.0, there are objects called "Course(s) of Action" used to describe mitigations to ATT&CK techniques. Similarly, the STIX 2.0 object called "Attack Pattern" describes techniques, etc. It should also be noted that Tactics are not an explicit object type in STIX 2.0, and they are referenced implicitly as kill chain phases within the other object types, as described in the tables below.
+
+#### Properties
+The following is a table mapping of ATT&CK properties, the old ATT&CK MediaWiki names, and the new STIX properties. Some of these properties are standard STIX properties, while others were custom-created for compatibility with ATT&CK. These properties are accessed from STIX objects as JSON properties.
+
+##### Migrating from MediaWiki
+
+##### Common properties (on all objects)
+ATT&CK Property | ATT&CK MediaWiki | STIX Properties
+--------------- | ---------------- | ---------------
+**Entry ID** | `Has ID` | `external_references[i].external_id` where `external_references[i].source_name == "mitre-attack"`
+**Entry URL** | `URL` | `external_references[i].url` where `external_references[i].source_name == "mitre-attack"`
+**Entry Title** | `Has display name` | `name`
+**Entry Text** | `Has description` | `description`
+**Citation** | `Citation reference` | `external_references`
+**Deprecated** | `Deprecated` | `x_mitre_deprecated`
+**Revoked** | `Not available via MediaWiki API` | `revoked`
+**Old ATT&CK ID** | `Not available via MediaWiki API` | `x_mitre_old_attack_id`
+
+
+##### Techniques
+ATT&CK Property | ATT&CK MediaWiki | STIX Properties
+--------------- | ---------------- | ---------------
+**Entry Title** | `Has technique name` | `name`
+**Tactic** | `Has tactic` | `kill_chain_phases[i].phase_name` where `kill_chain_phases[i].kill_chain_name == "mitre-attack"`
+**Description** | `Has technical description` | `description`
+**Mitigation** | `Has mitigation` | `relationship` where `relationship_type == "mitigates"`, points from a source object with `type=="course-of-action"`, which contains a `description`
+**Detection** | `Has detection` | `description` (inline heading of Detection)
+**Examples** | in software, groups as `Has technique` | `relationship`, points from the `attack-pattern` to and from `malware`, `tool`, and `intrusion-set`
+**Platform** | `Has platform` | `x_mitre_platforms`
+**Data Sources** | `Has data source` | `x_mitre_data_sources`
+**Permissions Required** | `Requires permissions` | `x_mitre_permissions_required`
+**Effective Permissions** | `Has effective permissions` | `x_mitre_effective_permissions`
+**Defense Bypassed** | `Bypasses defense` | `x_mitre_defense_bypassed`
+**System Requirements** | `Has system requirements` | `x_mitre_system_requirements`
+**Network Requirements** | `Has network requirements` | `x_mitre_network_requirements`
+**Remote Support** | `Has remote support` | `x_mitre_remote_support`
+**Contributors** | `Has contributor` | `x_mitre_contributors`
+**Impact Type** | `Not available via MediaWiki API` | `x_mitre_impact_type`
+
+
+##### Software
+ATT&CK Property | ATT&CK MediaWiki | STIX Properties
+--------------- | ---------------- | ---------------
+**Techniques Used** | `Has technique` | `relationship` where `relationship_type == "uses"`, points to a `target` object with `type== "attack-pattern"`
+**Aliases** | `Has alias` | `x_mitre_aliases`
+**Groups** | `Has groups` | `relationship` where `relationship_type == "uses"`, points from a `source` object with `type== "intrusion-set"`
+**Contributors** | `Has contributor` | `x_mitre_contributors`
+
+##### Groups
+ATT&CK Property | ATT&CK MediaWiki | STIX Properties
+--------------- | ---------------- | ---------------
+**Techniques Used** | `Has technique` | relationship where `relationship_type == "uses"`, points to a `target` object with `type == "attack-pattern"`
+**Alias Descriptions** | `Has alias` | `aliases`
+**Software** | `Has groups` | `relationship` where `relationship_type == "uses"`, points to a `target` object with `type== "malware" or "tool"`
+**Contributors** | `Has contributor` | `x_mitre_contributors`
\ No newline at end of file
diff --git a/USAGE.md b/USAGE.md
new file mode 100644
index 0000000..35da52e
--- /dev/null
+++ b/USAGE.md
@@ -0,0 +1,511 @@
+# ATT&CK知识图谱增删改查后端使用说明
+本后端支持基本的增删改查操作,以下为详情
+
+## 1. 返回码与含义
+
+|返回码|含义|
+|:----:|:----|
+|0|OK|
+|1|REQUEST_ERROR|
+|2|INTERNAL_ERROR|
+|3|NO_RECORD|
+|4|ALREADY_EXIST|
+
+详见 `uestc.zhanghanwen.ATTCK.Wrappers.ResponseWrapper`
+
+## 2. 查询操作
+
+### URL
+>http://localhost:8080/query
+>
+>method: `GET`, `POST`
+
+### 支持查询方式
+1. 提交HTTP参数查询名称或Mitre ID
+ #### 案例1
+ >MockHttpServletRequest:
+ HTTP Method = POST
+ Request URI = /query
+ Parameters = {name=[Initial Access]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController#queryObject(String, String)
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"579"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[{"description":"The adversary is trying to get into your network.\n\nInitial Access consists of techniques that use various entry vectors to gain their initial foothold within a network. Techniques used to gain a foothold include targeted spearphishing and exploiting weaknesses on public-facing web servers. Footholds gained through initial access may allow for continued access, like valid accounts and use of external remote services, or may be limited-use due to changing passwords.","mitre_id":"TA0001","name":"Initial Access"}],"msg":"OK","detail":""}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+ #### 案例2
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /query
+ Parameters = {id=[MT0001]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController#queryObject(String, String)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"81"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[{"mitre_id":"MT0001","name":"pre"}],"msg":"OK","detail":""}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+
+2. REST URL 查询 ID
+ >HTTP Method = GET
+ Request URI = /query/TA0001
+ Parameters = {}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController#queryObjectByMitreId(String)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"579"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[{"description":"The adversary is trying to get into your network.\n\nInitial Access consists of techniques that use various entry vectors to gain their initial foothold within a network. Techniques used to gain a foothold include targeted spearphishing and exploiting weaknesses on public-facing web servers. Footholds gained through initial access may allow for continued access, like valid accounts and use of external remote services, or may be limited-use due to changing passwords.","mitre_id":"TA0001","name":"Initial Access"}],"msg":"OK","detail":""}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+3. 查询某一类型
+
+ #### 案例1,分页
+
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /query/type/technique
+ Parameters = {page=[5]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController#queryType(String, boolean, int, int)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"23987"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[{...},...,{...}],"msg":"OK","detail":""}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+ #### 案例2, 不分页
+
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /query/type/matrix
+ Parameters = {get_all=[true]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController#queryType(String, boolean, int, int)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"123"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[{"mitre_id":"MT0001","name":"pre"},{"mitre_id":"MT0002","name":"enterprise"}],"msg":"OK","detail":""}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+4. 查询相关
+
+ #### 案例1,查询某一节点为起始的所有相关
+
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /query/MT0001/related
+ Parameters = {}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController#queryRelatedByStartNodeMitreId(String)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"6091"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[{"original":{"mitre_id":"MT0001","name":"pre"}},{"related":[{...},...,{...}]}],"msg":"OK","detail":""}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+ #### 案例2,查询两个节点之间的关系
+
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /query/related
+ Parameters = {start_id=[MT0002], end_id=[TA0001]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController#queryRelationshipByStartAndEndNodeMitreId(String, String)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"66"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[{"name":"contains"}],"msg":"OK","detail":""}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+## 3. 增加操作
+### URL
+>http://localhost:8080/create
+>
+>method: `GET`, `POST`
+### 支持增加方式
+
+1. 增加节点
+
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /create/node
+ Parameters = {value=[{"name":"test1","mitre_id":"A","type":"matrix"}]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.CreateController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.CreateController#createNode(String)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"78"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[{"mitre_id":"A","name":"test1"}],"msg":"OK","detail":""}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+2. 增加关系
+
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /create/relationship
+ Parameters = {start_id=[A], end_id=[B], relationship=[in]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.CreateController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.CreateController#createRelationship(String, String, String)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"80"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[],"msg":"OK","detail":"created relationship: 'A' in 'B'."}
+ Forwarded URL = null
+ Redirected URL = null
+
+## 4. 修改操作
+### URL
+>http://localhost:8080/update
+>
+>method: `GET`, `POST`
+### 支持修改方式
+
+1. 修改节点信息
+
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /update
+ Parameters = {value=[{"name":"test0","mitre_id":"A","type":"matrix"}]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.UpdateController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.UpdateController#updateNode(String)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"78"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[{"mitre_id":"A","name":"test0"}],"msg":"OK","detail":""}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+## 5. 删除操作
+### URL
+>http://localhost:8080/delete
+>
+>method: `GET`, `POST`
+### 支持删除方式
+
+1. 删除某个节点以及其所有关系
+
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /delete/node
+ Parameters = {id=[A]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.DeleteController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.DeleteController#deleteObjectAndRelationship(String)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"93"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[],"msg":"OK","detail":"Deleted node: 'A', deleted relationship: 'in'."}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
+
+2. 删除两个节点之间的关系
+
+ >MockHttpServletRequest:
+ HTTP Method = GET
+ Request URI = /delete/relationship
+ Parameters = {start_id=[A], end_id=[B]}
+ Headers = []
+ Body = null
+ Session Attrs = {}
+ >
+ >Handler:
+ Type = uestc.zhanghanwen.ATTCK.RestWebControllers.DeleteController
+ Method = uestc.zhanghanwen.ATTCK.RestWebControllers.DeleteController#deleteRelationship(String, String)
+ >
+ >Async:
+ Async started = false
+ Async result = null
+ >
+ >Resolved Exception:
+ Type = null
+ >
+ >ModelAndView:
+ View name = null
+ View = null
+ Model = null
+ >
+ >FlashMap:
+ Attributes = null
+ >
+ >MockHttpServletResponse:
+ Status = 200
+ Error message = null
+ Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"71"]
+ Content type = text/plain;charset=UTF-8
+ Body = {"status":0,"result":[],"msg":"OK","detail":"Deleted relationship: in"}
+ Forwarded URL = null
+ Redirected URL = null
+ Cookies = []
\ No newline at end of file
diff --git a/images/ATTCKApplication.png b/images/ATTCKApplication.png
new file mode 100644
index 0000000..69d0510
Binary files /dev/null and b/images/ATTCKApplication.png differ
diff --git a/images/PackagePOJOs.png b/images/PackagePOJOs.png
new file mode 100644
index 0000000..0a72fa4
Binary files /dev/null and b/images/PackagePOJOs.png differ
diff --git a/images/PackageRetrieveServices.png b/images/PackageRetrieveServices.png
new file mode 100644
index 0000000..28eec93
Binary files /dev/null and b/images/PackageRetrieveServices.png differ
diff --git a/images/RetrieveController.png b/images/RetrieveController.png
new file mode 100644
index 0000000..b416050
Binary files /dev/null and b/images/RetrieveController.png differ
diff --git a/images/Service.png b/images/Service.png
new file mode 100644
index 0000000..8a8d388
Binary files /dev/null and b/images/Service.png differ
diff --git a/images/ServiceBundle.png b/images/ServiceBundle.png
new file mode 100644
index 0000000..d834774
Binary files /dev/null and b/images/ServiceBundle.png differ
diff --git a/images/ServiceImplement.png b/images/ServiceImplement.png
new file mode 100644
index 0000000..ef7ad86
Binary files /dev/null and b/images/ServiceImplement.png differ
diff --git a/mvnw b/mvnw
new file mode 100755
index 0000000..a16b543
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100644
index 0000000..c8d4337
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..814d166
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,97 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.3.9.RELEASE
+
+
+ uestc.zhanghanwen
+ ATTCK
+ 1.0
+ ATTCK
+ Backend for ATT&CK knowledge on Neo4j graph database.
+
+
+ 11.0.10
+
+
+
+
+
+
+ alimaven
+ aliyun maven
+ http://maven.aliyun.com/nexus/content/groups/public/
+
+
+
+
+
+ org.neo4j
+ neo4j-ogm-http-driver
+ 3.2.21
+
+
+ org.neo4j
+ neo4j-ogm-core
+ 3.2.21
+
+
+
+ org.springframework.data
+ spring-data-neo4j
+ 5.3.7.RELEASE
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.75
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+ org.jetbrains
+ annotations
+ 20.1.0
+ compile
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ RELEASE
+ test
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/ATTCKApplication.java b/src/main/java/uestc/zhanghanwen/ATTCK/ATTCKApplication.java
new file mode 100644
index 0000000..cae1e8d
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/ATTCKApplication.java
@@ -0,0 +1,34 @@
+package uestc.zhanghanwen.ATTCK;
+
+import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.boot.SpringApplication;
+import lombok.NoArgsConstructor;
+
+/**
+ * The main entrance for the Spring Applications.
+ * This Application uses Springboot framework, for more information about the frameworks,
+ * please refer to pom.xml
+ *
+ * @see uestc.zhanghanwen.ATTCK.RestWebControllers controllers
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Configuration
+@NoArgsConstructor
+@SpringBootApplication
+@EnableNeo4jRepositories
+@EnableTransactionManagement(proxyTargetClass = true)
+public class ATTCKApplication {
+
+ /**
+ * All magics start from here...
+ *
+ * @param args {@code null}
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(ATTCKApplication.class, args);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/ATTCKService.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/ATTCKService.java
new file mode 100644
index 0000000..bf4dd28
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/ATTCKService.java
@@ -0,0 +1,69 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices;
+
+import uestc.zhanghanwen.ATTCK.Repositories.NodeRepository;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import org.springframework.stereotype.Service;
+import com.alibaba.fastjson.JSONObject;
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.Data;
+
+/**
+ * The abstract class for all single services.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Data
+@Service
+public abstract class ATTCKService> implements ServiceInterface {
+
+ /**
+ * The {@link NodeRepository} of the specified inherited class of {@link GraphNode}
+ */
+ protected NR repo;
+
+ /**
+ * Check if node exist
+ *
+ * @throws Exception if {@link NodeRepository#findByMitreId} fails
+ * @param mitreId mitre id to check
+ * @return ture if exists
+ */
+ public Boolean isNodeExist(String mitreId) throws Exception {
+ return this.getRepo().findByMitreId(mitreId).size() != 0;
+ }
+
+ /**
+ * Check if relationship exist
+ *
+ * @throws Exception if {@link NodeRepository#findRelationshipByMitreId} fails
+ * @param startNodeMitreId start node mitre id
+ * @param endNodeMitreId end node mitre id
+ * @return true if exists
+ */
+ public Boolean isRelationshipExist(String startNodeMitreId, String endNodeMitreId) throws Exception {
+ return this.getRepo().findRelationshipByMitreId(startNodeMitreId, endNodeMitreId) != null;
+ }
+
+ /**
+ * Save one node into the graph database.
+ * @param node in form of {@link JSONObject}
+ * @return {@link ResultWrapper} of all queried results.
+ * @throws Exception if {@link NodeRepository#save} fails or the mitre id of the saved node is not matched
+ * as the expected input, then rollback.
+ */
+ protected ResultWrapper save(JSONObject node) throws Exception {
+
+ @SuppressWarnings("unchecked")
+ Class clazz = (Class)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
+ GN graphNode = this.getRepo().save(JSONObject.toJavaObject(node, clazz));
+
+ List list = new ArrayList<>();
+ list.add(graphNode);
+
+ return ResultWrapper.resultFromList(list);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/CreateService.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/CreateService.java
new file mode 100644
index 0000000..2051f8c
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/CreateService.java
@@ -0,0 +1,37 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices;
+
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * The interface for all Services inside.
+ * This is the interface oriented mode, that makes easier for {@link CreateServiceBundle} to manage all services.
+ *
+ * @see CreateServiceBundle
+ * @author zhanghanwen
+ * @version 1.0
+ */
+public interface CreateService {
+
+ /**
+ * create one node.
+ *
+ * @param node in form of {@link JSONObject}
+ * @throws Exception if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository#save} fails
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ ResultWrapper createNode(JSONObject node) throws Exception;
+
+ /**
+ * create a relationship by specifying start node and end node mitre id, and type.
+ *
+ * @throws Exception if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository} fails
+ * @param type type of node
+ * @param startNodeMitreId mitre id
+ * @param endNodeMitreId mitre id
+ * @param relationship relationship to create
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ ResultWrapper createRelationship(String type, String startNodeMitreId, String endNodeMitreId, String relationship)
+ throws Exception;
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/CreateServiceBundle.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/CreateServiceBundle.java
new file mode 100644
index 0000000..af6a044
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/CreateServiceBundle.java
@@ -0,0 +1,130 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.Implements.*;
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.ServiceBundle;
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import uestc.zhanghanwen.ATTCK.Wrappers.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * This is the consultation class for all POJO services.
+ * That all services are accessed by one single group of API provided by this class, which is
+ * {@link CreateService}.
+ *
+ * @see CreateService
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class CreateServiceBundle extends ServiceBundle {
+
+ /**
+ * Autowire({@link Autowired}) of spring services listed below. The service implements are listed as below.
+ * The services are managed and accessed by a simple array of type {@link CreateService}.
+ *
+ * @param mitigationService {@link CreateMitigationServiceImpl}
+ * @param techniqueService {@link CreateTechniqueServiceImpl}
+ * @param softwareService {@link CreateSoftwareServiceImpl}
+ * @param tacticService {@link CreateTacticServiceImpl}
+ * @param matrixService {@link CreateMatrixServiceImpl}
+ * @param groupService {@link CreateGroupServiceImpl}
+ */
+ @Autowired
+ public CreateServiceBundle(
+ CreateMitigationServiceImpl mitigationService,
+ CreateTechniqueServiceImpl techniqueService,
+ CreateSoftwareServiceImpl softwareService,
+ CreateTacticServiceImpl tacticService,
+ CreateMatrixServiceImpl matrixService,
+ CreateGroupServiceImpl groupService
+ ) {
+ this.getServices().put("mitigation", mitigationService);
+ this.getServices().put("technique", techniqueService);
+ this.getServices().put("software", softwareService);
+ this.getServices().put("tactic", tacticService);
+ this.getServices().put("matrix", matrixService);
+ this.getServices().put("group", groupService);
+ }
+
+ /**
+ * create a node.
+ *
+ * @param query {@link QueryWrapper} containing the node.
+ * @return {@link ResponseWrapper} of response.
+ */
+ public ResponseWrapper createNode(QueryWrapper query) {
+
+ JSONObject node = query.getNodes().getJSONObject(0);
+ String type = query.getType();
+ ResponseWrapper response = new ResponseWrapper();
+
+ CreateService service = (CreateService) this.getService(type);
+
+ if (service == null) {
+ response.addAll(ResultWrapper.wrongTypeResult(type));
+ return response;
+ }
+
+ if (this.isNodeExist(query.getMitreId())) {
+ response.setStatus(ResponseWrapper.ALREADY_EXIST);
+ response.setMsg(ResponseWrapper.ALREADY_EXIST_MSG);
+ return response;
+ }
+
+ try {
+ response.addAll(service.createNode(node));
+
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ }
+ return response;
+ }
+
+ /**
+ * create a pair of relationships by specifying start node and end node mitre id.
+ *
+ * @param query {@link QueryWrapper} start node and end node mitre id
+ * @return {@link ResponseWrapper} of response.
+ */
+ public ResponseWrapper createRelationship(QueryWrapper query) {
+
+ String startNodeMitreId = query.getNodes().getJSONObject(0).getString("mitre_id");
+ String endNodeMitreId = query.getNodes().getJSONObject(1).getString("mitre_id");
+ String type = GraphNode.getTypeFromMitreId(startNodeMitreId);
+ String relationship = query.getRelationship();
+
+ ResponseWrapper response = new ResponseWrapper();
+
+ CreateService service = (CreateService) this.getService(type);
+
+ if (service == null) {
+ response.addAll(ResultWrapper.wrongTypeResult(type));
+ return response;
+ }
+
+ if (!this.isStartAndEndNodeExists(startNodeMitreId, endNodeMitreId)) {
+ response.setStatus(ResponseWrapper.NO_RECORD);
+ response.setMsg(ResponseWrapper.NO_RECORD_MSG);
+ response.setDetail("the start node or the end node is not found.");
+ return response;
+ }
+
+ if (this.isRelationshipExist(startNodeMitreId, endNodeMitreId)) {
+ response.setStatus(ResponseWrapper.ALREADY_EXIST);
+ response.setMsg(ResponseWrapper.ALREADY_EXIST_MSG);
+ response.setDetail("The relationship between object '"
+ + startNodeMitreId + "' and '" + endNodeMitreId + "' object already exists");
+ return response;
+ }
+
+ try {
+ response.addAll(service.createRelationship(type, startNodeMitreId, endNodeMitreId, relationship));
+
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ }
+ return response;
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateGroupServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateGroupServiceImpl.java
new file mode 100644
index 0000000..b9eb6ab
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateGroupServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.GroupRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Group;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is the service implementation class for {@link GroupRepo}.
+ * The return types are all {@code List}
+ *
+ * @see GroupRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class CreateGroupServiceImpl extends CreateServiceImplement {
+
+ @Autowired
+ public CreateGroupServiceImpl(GroupRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateMatrixServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateMatrixServiceImpl.java
new file mode 100644
index 0000000..5190101
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateMatrixServiceImpl.java
@@ -0,0 +1,24 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.MatrixRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Matrix;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * This is the service implementation class for {@link MatrixRepo}.
+ * The return types are all {@code List}
+ *
+ * @see MatrixRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class CreateMatrixServiceImpl extends CreateServiceImplement {
+
+ @Autowired
+ public CreateMatrixServiceImpl(MatrixRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateMitigationServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateMitigationServiceImpl.java
new file mode 100644
index 0000000..2eaac34
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateMitigationServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.MitigationRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Mitigation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is the service implementation class for {@link MitigationRepo}.
+ * The return types are all {@code List}
+ *
+ * @see MitigationRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class CreateMitigationServiceImpl extends CreateServiceImplement {
+
+ @Autowired
+ public CreateMitigationServiceImpl(MitigationRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateServiceImplement.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateServiceImplement.java
new file mode 100644
index 0000000..ecfec71
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateServiceImplement.java
@@ -0,0 +1,89 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.CreateService;
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.ATTCKService;
+import uestc.zhanghanwen.ATTCK.Repositories.NodeRepository;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import org.springframework.transaction.annotation.Transactional;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONArray;
+
+/**
+ * This class has the implementation of methods in {@link CreateService} used in
+ * {@link uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.CreateServiceBundle}.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+abstract class CreateServiceImplement>
+ extends ATTCKService
+ implements CreateService {
+
+ /**
+ * create one node using the {@link CreateServiceImplement#repo}.
+ *
+ * @param node node
+ * @return {@link ResultWrapper} of all queried results.
+ * @throws Exception if {@link NodeRepository#save} fails or the mitre id of the saved node is not matched
+ * as the expected input, then rollback.
+ * @see ATTCKService#save
+ */
+ @Override
+ @Transactional
+ public ResultWrapper createNode(JSONObject node) throws Exception {
+ return this.save(node);
+ }
+
+ /**
+ * create a relationship by specifying start node and end node mitre id, and type
+ * using the {@link CreateServiceImplement#repo}.
+ *
+ * @param type one of {@link uestc.zhanghanwen.ATTCK.POJOs}
+ * @param startNodeMitreId start node mitre id
+ * @param endNodeMitreId end node mitre id
+ * @return {@link JSONArray} of all queried results.
+ * @throws Exception if {@link NodeRepository#save} fails or the mitre id of the saved node is not matched
+ * as the expected input, then rollback.
+ */
+ @Override
+ @Transactional
+ public ResultWrapper createRelationship(String type,
+ String startNodeMitreId,
+ String endNodeMitreId,
+ String relationship) throws Exception {
+
+ ResultWrapper result;
+
+ switch (relationship) {
+ case "contains":
+ this.getRepo().createContainsRelationshipByMitreId(startNodeMitreId, endNodeMitreId);
+ break;
+
+ case "in":
+ this.getRepo().createInRelationshipByMitreId(startNodeMitreId, endNodeMitreId);
+ break;
+
+ case "uses":
+ this.getRepo().createUsesRelationshipByMitreId(startNodeMitreId, endNodeMitreId);
+ break;
+
+ case "is used by":
+ this.getRepo().createUsedByRelationshipByMitreId(startNodeMitreId, endNodeMitreId);
+ break;
+
+ default:
+ result = new ResultWrapper(ResultWrapper.REQUEST_ERROR);
+ result.setMsgSpec("Unable to create relationship, because cannot found a relationship of type "
+ + relationship);
+ return result;
+ }
+
+ result = new ResultWrapper(ResultWrapper.OK);
+ result.setMsgSpec("created relationship: '" + startNodeMitreId + "' "
+ + relationship + " '" + endNodeMitreId + "'.");
+ result.setResult(new JSONArray(0));
+
+ return result;
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateSoftwareServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateSoftwareServiceImpl.java
new file mode 100644
index 0000000..dc40a14
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateSoftwareServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.SoftwareRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Software;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is the service implementation class for {@link SoftwareRepo}.
+ * The return types are all {@code List}
+ *
+ * @see SoftwareRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class CreateSoftwareServiceImpl extends CreateServiceImplement {
+
+ @Autowired
+ public CreateSoftwareServiceImpl(SoftwareRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateTacticServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateTacticServiceImpl.java
new file mode 100644
index 0000000..0e501ab
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateTacticServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Tactic;
+import uestc.zhanghanwen.ATTCK.Repositories.TacticRepo;
+
+/**
+ * This is the service implementation class for {@link TacticRepo}.
+ * The return types are all {@code List}
+ *
+ * @see TacticRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class CreateTacticServiceImpl extends CreateServiceImplement {
+
+ @Autowired
+ public CreateTacticServiceImpl(TacticRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateTechniqueServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateTechniqueServiceImpl.java
new file mode 100644
index 0000000..ea25a45
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/CreateTechniqueServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Technique;
+import uestc.zhanghanwen.ATTCK.Repositories.TechniqueRepo;
+
+/**
+ * This is the service implementation class for {@link TechniqueRepo}.
+ * The return types are all {@code List}
+ *
+ * @see TechniqueRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class CreateTechniqueServiceImpl extends CreateServiceImplement {
+
+ @Autowired
+ public CreateTechniqueServiceImpl(TechniqueRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/package-info.java
new file mode 100644
index 0000000..9d74f24
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/Implements/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The implementation of all services.
+ */
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.Implements;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/package-info.java
new file mode 100644
index 0000000..4147cef
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/CreateServices/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * The SpringBoot service for {@link uestc.zhanghanwen.ATTCK.RestWebControllers.CreateController}
+ * of different type {@link uestc.zhanghanwen.ATTCK.POJOs.GraphNode}
+ */
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/DeleteService.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/DeleteService.java
new file mode 100644
index 0000000..d594c24
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/DeleteService.java
@@ -0,0 +1,33 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices;
+
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+
+/**
+ * The interface for all Services inside.
+ * This is the interface oriented mode, that makes easier for {@link DeleteServiceBundle} to manage all services.
+ *
+ * @see DeleteServiceBundle
+ * @author zhanghanwen
+ * @version 1.0
+ */
+public interface DeleteService {
+
+ /**
+ * delete one node.
+ *
+ * @throws Exception if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository#deleteByMitreId} fails
+ * @param mitreId mitre id
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ ResultWrapper deleteOne(String mitreId) throws Exception;
+
+ /**
+ * delete a relationship by specifying start node and end node mitre id.
+ *
+ * @throws Exception if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository#deleteRelationships} fails
+ * @param startNodeMitreId mitre id
+ * @param endNodeMitreId mitre id
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ ResultWrapper deleteRelationship(String startNodeMitreId, String endNodeMitreId) throws Exception;
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/DeleteServiceBundle.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/DeleteServiceBundle.java
new file mode 100644
index 0000000..49a82d4
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/DeleteServiceBundle.java
@@ -0,0 +1,131 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.Implements.*;
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.ServiceBundle;
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResponseWrapper;
+import uestc.zhanghanwen.ATTCK.Wrappers.QueryWrapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+
+/**
+ * This is the consultation class for all POJO services.
+ * That all services are accessed by one single group of API provided by this class, that is,
+ * {@link DeleteService}.
+ *
+ * @see DeleteService
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class DeleteServiceBundle extends ServiceBundle {
+
+ /**
+ * Autowire({@link Autowired}) of spring services listed below. The service implements are listed as below.
+ * The services are managed and accessed by a simple array of type {@link DeleteService}.
+ *
+ * @param mitigationService {@link DeleteMitigationServiceImpl}
+ * @param techniqueService {@link DeleteTechniqueServiceImpl}
+ * @param softwareService {@link DeleteSoftwareServiceImpl}
+ * @param tacticService {@link DeleteTacticServiceImpl}
+ * @param matrixService {@link DeleteMatrixServiceImpl}
+ * @param groupService {@link DeleteGroupServiceImpl}
+ */
+ @Autowired
+ public DeleteServiceBundle(
+ DeleteMitigationServiceImpl mitigationService,
+ DeleteTechniqueServiceImpl techniqueService,
+ DeleteSoftwareServiceImpl softwareService,
+ DeleteTacticServiceImpl tacticService,
+ DeleteMatrixServiceImpl matrixService,
+ DeleteGroupServiceImpl groupService
+ ) {
+ this.getServices().put("mitigation", mitigationService);
+ this.getServices().put("technique", techniqueService);
+ this.getServices().put("software", softwareService);
+ this.getServices().put("tactic", tacticService);
+ this.getServices().put("matrix", matrixService);
+ this.getServices().put("group", groupService);
+ }
+
+ /**
+ * delete a node.
+ *
+ * @param query {@link QueryWrapper} containing the node.
+ * @return {@link ResponseWrapper} of response.
+ */
+ public ResponseWrapper deleteNode(QueryWrapper query) {
+
+ String mitreId = query.getMitreId();
+ String type = GraphNode.getTypeFromMitreId(mitreId);
+ ResponseWrapper response = new ResponseWrapper();
+
+ DeleteService service = (DeleteService) this.getService(type);
+
+ if (service == null) {
+ response.addAll(ResultWrapper.wrongTypeResult(type));
+ return response;
+ }
+
+ if (!this.isNodeExist(mitreId)) {
+ response.setStatus(ResponseWrapper.NO_RECORD);
+ response.setMsg(ResponseWrapper.NO_RECORD_MSG);
+ response.setDetail("cannot delete because the start node of mitre id '" + mitreId + "' is not found.");
+ return response;
+ }
+
+ try {
+ ResultWrapper result = service.deleteOne(mitreId);
+ response.addAll(result);
+
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ }
+ return response;
+ }
+
+ /**
+ * delete a pair of relationships by specifying start node and end node mitre id.
+ *
+ * @param query {@link QueryWrapper} start node and end node mitre id
+ * @return {@link ResponseWrapper} of response.
+ */
+ public ResponseWrapper deleteRelationship(QueryWrapper query) {
+
+ String startNodeMitreId = query.getNodes().getJSONObject(0).getString("mitre_id");
+ String endNodeMitreId = query.getNodes().getJSONObject(1).getString("mitre_id");
+ String type = query.getType();
+ ResponseWrapper response = new ResponseWrapper();
+
+ DeleteService service = (DeleteService) this.getService(type);
+
+ if (service == null) {
+ response.addAll(ResultWrapper.wrongTypeResult(type));
+ return response;
+ }
+
+ if (!this.isStartAndEndNodeExists(startNodeMitreId, endNodeMitreId)) {
+ response.setStatus(ResponseWrapper.NO_RECORD);
+ response.setMsg(ResponseWrapper.NO_RECORD_MSG);
+ response.setDetail("the start node or the end node is not found.");
+ return response;
+ }
+
+ if (!this.isRelationshipExist(startNodeMitreId, endNodeMitreId)) {
+ response.setStatus(ResponseWrapper.NO_RECORD);
+ response.setMsg(ResponseWrapper.NO_RECORD_MSG);
+ response.setDetail("The relationship between object '"
+ + startNodeMitreId + "' and '" + endNodeMitreId + "' object already exists");
+ return response;
+ }
+
+ try {
+ response.addAll(service.deleteRelationship(startNodeMitreId, endNodeMitreId));
+
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ }
+ return response;
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteGroupServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteGroupServiceImpl.java
new file mode 100644
index 0000000..f7bf42f
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteGroupServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Group;
+import uestc.zhanghanwen.ATTCK.Repositories.GroupRepo;
+
+/**
+ * This is the service implementation class for {@link GroupRepo}.
+ * The return types are all {@code List}
+ *
+ * @see GroupRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class DeleteGroupServiceImpl extends DeleteServiceImplement {
+
+ @Autowired
+ public DeleteGroupServiceImpl(GroupRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteMatrixServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteMatrixServiceImpl.java
new file mode 100644
index 0000000..ae43ac1
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteMatrixServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Matrix;
+import uestc.zhanghanwen.ATTCK.Repositories.MatrixRepo;
+
+/**
+ * This is the service implementation class for {@link MatrixRepo}.
+ * The return types are all {@code List}
+ *
+ * @see MatrixRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class DeleteMatrixServiceImpl extends DeleteServiceImplement {
+
+ @Autowired
+ public DeleteMatrixServiceImpl(MatrixRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteMitigationServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteMitigationServiceImpl.java
new file mode 100644
index 0000000..2a21341
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteMitigationServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Mitigation;
+import uestc.zhanghanwen.ATTCK.Repositories.MitigationRepo;
+
+/**
+ * This is the service implementation class for {@link MitigationRepo}.
+ * The return types are all {@code List}
+ *
+ * @see MitigationRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class DeleteMitigationServiceImpl extends DeleteServiceImplement {
+
+ @Autowired
+ public DeleteMitigationServiceImpl(MitigationRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteServiceImplement.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteServiceImplement.java
new file mode 100644
index 0000000..add7638
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteServiceImplement.java
@@ -0,0 +1,64 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.DeleteService;
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.ATTCKService;
+import uestc.zhanghanwen.ATTCK.Repositories.NodeRepository;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import org.springframework.transaction.annotation.Transactional;
+import com.alibaba.fastjson.JSONArray;
+
+/**
+ * This class has the implementation of methods,
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+abstract class DeleteServiceImplement>
+ extends ATTCKService
+ implements DeleteService {
+
+ /**
+ * delete one node.
+ *
+ * @param mitreId mitre id
+ * @throws Exception if {@link NodeRepository#save} fails or the mitre id of the saved node is not matched
+ * as the expected input, then rollback.
+ * @return {@link JSONArray} of all queried results.
+ */
+ @Override
+ @Transactional
+ public ResultWrapper deleteOne(String mitreId) throws Exception {
+
+ this.getRepo().deleteRelationships(mitreId);
+ this.getRepo().deleteByMitreId(mitreId);
+
+ ResultWrapper result = new ResultWrapper(ResultWrapper.OK);
+ result.setMsgSpec("Deleted node: '" + mitreId + "'.");
+ result.setResult(new JSONArray());
+
+ return result;
+ }
+
+ /**
+ * delete a relationship by specifying start node and end node mitre id.
+ *
+ * @param startNodeMitreId mitre id
+ * @param endNodeMitreId mitre id
+ * @throws Exception if {@link NodeRepository#save} fails or the mitre id of the saved node is not matched
+ * as the expected input, then rollback.
+ * @return {@link JSONArray} of all queried results.
+ */
+ @Override
+ @Transactional
+ public ResultWrapper deleteRelationship(String startNodeMitreId, String endNodeMitreId) throws Exception {
+
+ this.getRepo().deleteRelationshipByStartNodeMitreId(startNodeMitreId, endNodeMitreId);
+
+ ResultWrapper result = new ResultWrapper(ResultWrapper.OK);
+ result.setMsgSpec("Relationship deleted.");
+ result.setResult(new JSONArray());
+
+ return result;
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteSoftwareServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteSoftwareServiceImpl.java
new file mode 100644
index 0000000..fc8c810
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteSoftwareServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Software;
+import uestc.zhanghanwen.ATTCK.Repositories.SoftwareRepo;
+
+/**
+ * This is the service implementation class for {@link SoftwareRepo}.
+ * The return types are all {@code List}
+ *
+ * @see SoftwareRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class DeleteSoftwareServiceImpl extends DeleteServiceImplement {
+
+ @Autowired
+ public DeleteSoftwareServiceImpl(SoftwareRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteTacticServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteTacticServiceImpl.java
new file mode 100644
index 0000000..abd51d5
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteTacticServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Tactic;
+import uestc.zhanghanwen.ATTCK.Repositories.TacticRepo;
+
+/**
+ * This is the service implementation class for {@link TacticRepo}.
+ * The return types are all {@code List}
+ *
+ * @see TacticRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class DeleteTacticServiceImpl extends DeleteServiceImplement {
+
+ @Autowired
+ public DeleteTacticServiceImpl(TacticRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteTechniqueServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteTechniqueServiceImpl.java
new file mode 100644
index 0000000..27643d6
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/DeleteTechniqueServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Technique;
+import uestc.zhanghanwen.ATTCK.Repositories.TechniqueRepo;
+
+/**
+ * This is the service implementation class for {@link TechniqueRepo}.
+ * The return types are all {@code List}
+ *
+ * @see TechniqueRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class DeleteTechniqueServiceImpl extends DeleteServiceImplement {
+
+ @Autowired
+ public DeleteTechniqueServiceImpl(TechniqueRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/package-info.java
new file mode 100644
index 0000000..71cb7c4
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/Implements/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The implementation of all services.
+ */
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.Implements;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/package-info.java
new file mode 100644
index 0000000..8286828
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/DeleteServices/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * The SpringBoot service for {@link uestc.zhanghanwen.ATTCK.RestWebControllers.DeleteController}
+ * of different type {@link uestc.zhanghanwen.ATTCK.POJOs.GraphNode}
+ */
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveGroupServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveGroupServiceImpl.java
new file mode 100644
index 0000000..f8d822d
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveGroupServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.GroupRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Group;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is the service implementation class for {@link GroupRepo}.
+ * The return types are all {@code List}
+ *
+ * @see GroupRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class RetrieveGroupServiceImpl extends RetrieveServiceImplement {
+
+ @Autowired
+ public RetrieveGroupServiceImpl(GroupRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveMatrixServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveMatrixServiceImpl.java
new file mode 100644
index 0000000..0dc6087
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveMatrixServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.MatrixRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Matrix;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is the service implementation class for {@link MatrixRepo}.
+ * The return types are all {@code List}
+ *
+ * @see MatrixRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class RetrieveMatrixServiceImpl extends RetrieveServiceImplement {
+
+ @Autowired
+ public RetrieveMatrixServiceImpl(MatrixRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveMitigationServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveMitigationServiceImpl.java
new file mode 100644
index 0000000..1ddb479
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveMitigationServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.MitigationRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Mitigation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is the service implementation class for {@link MitigationRepo}.
+ * The return types are all {@code List}
+ *
+ * @see MitigationRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class RetrieveMitigationServiceImpl extends RetrieveServiceImplement {
+
+ @Autowired
+ public RetrieveMitigationServiceImpl(MitigationRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveServiceImplement.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveServiceImplement.java
new file mode 100644
index 0000000..7490b1f
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveServiceImplement.java
@@ -0,0 +1,126 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.RetrieveService;
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.ATTCKService;
+import uestc.zhanghanwen.ATTCK.Repositories.NodeRepository;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONArray;
+import java.util.List;
+
+/**
+ * This class has the implementation of methods in {@link RetrieveService} used in
+ * {@link uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.RetrieveServiceBundle},
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+abstract class RetrieveServiceImplement>
+ extends ATTCKService
+ implements RetrieveService {
+
+ /**
+ * Get the node by its name or mitre id.
+ *
+ * @throws Exception if {@link NodeRepository#findByMitreId} fails
+ * @param mitreId mitre id
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ @Override
+ public ResultWrapper findByMitreId(String mitreId) throws Exception {
+ List list = this.getRepo().findByMitreId(mitreId);
+ return ResultWrapper.resultFromList(list);
+ }
+
+ /**
+ * Get the node by it's name.
+ *
+ * @throws Exception if {@link NodeRepository#findByName} fails
+ * @param name name
+ * @return {@link ResultWrapper} of the queried result.
+ */
+ @Override
+ public ResultWrapper findByName(String name) throws Exception {
+ List list;
+ list = this.getRepo().findByName(name);
+ return ResultWrapper.resultFromList(list);
+ }
+
+
+ /**
+ * Get all nodes by type, with page and size specified.
+ * if page is -1, then return all results.
+ *
+ * @throws Exception if {@link NodeRepository#findAll} fails
+ * @param type the specified type.
+ * @param page page, start from 0.
+ * @param size size, how many records in one page.
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ @Override
+ public ResultWrapper findAll(String type, int page, int size) throws Exception {
+
+ List list;
+ if (page != -1) {
+ list = this.getRepo().findAll(
+ PageRequest.of(
+ page,
+ size,
+ Sort.by(Sort.DEFAULT_DIRECTION, "mitre_id")
+ )
+ ).toList();
+ } else {
+ list = (List) this.getRepo().findAll();
+ }
+
+ return ResultWrapper.resultFromList(list);
+ }
+
+ /**
+ * Find all related nodes of one node.
+ *
+ * @throws Exception if {@link NodeRepository#findRelatedByStartNodeMitreId} fails
+ * @param startNodeMitreId mitre id of the start node.
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ @Override
+ public ResultWrapper findRelatedNodes(String startNodeMitreId) throws Exception {
+
+ List results = this.getRepo().findRelatedByStartNodeMitreId(startNodeMitreId);
+ return ResultWrapper.resultFromList(results);
+ }
+
+ /**
+ * Return the specified relationship name between two given nodes.
+ *
+ * @throws Exception if {@link NodeRepository#findRelationshipByMitreId} fails
+ * @param startNodeMitreId the mitre id of the start node.
+ * @param endNodeMitreId the mitre id of the end node.
+ * @return the relationship name in {@link String}
+ */
+ @Override
+ public ResultWrapper findRelationship(String startNodeMitreId, String endNodeMitreId) throws Exception {
+
+ String relationship;
+
+ relationship = this.getRepo().findRelationshipByMitreId(startNodeMitreId, endNodeMitreId);
+
+ ResultWrapper result = new ResultWrapper();
+
+ if (relationship == null) {
+ return new ResultWrapper(ResultWrapper.NO_RECORD);
+ }
+
+ result.setStatusCode(ResultWrapper.OK);
+ JSONObject name = new JSONObject(1);
+ name.put("name", relationship);
+ JSONArray nameArray = new JSONArray();
+ nameArray.add(name);
+ result.setResult(nameArray);
+
+ return result;
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveSoftwareServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveSoftwareServiceImpl.java
new file mode 100644
index 0000000..0a7ab10
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveSoftwareServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.SoftwareRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Software;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is the service implementation class for {@link SoftwareRepo}.
+ * The return types are all {@code List}
+ *
+ * @see SoftwareRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class RetrieveSoftwareServiceImpl extends RetrieveServiceImplement {
+
+ @Autowired
+ public RetrieveSoftwareServiceImpl(SoftwareRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveTacticServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveTacticServiceImpl.java
new file mode 100644
index 0000000..d929819
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveTacticServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.TacticRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Tactic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is the service implementation class for {@link TacticRepo}.
+ * The return types are all {@code List}
+ *
+ * @see TacticRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class RetrieveTacticServiceImpl extends RetrieveServiceImplement {
+
+ @Autowired
+ public RetrieveTacticServiceImpl(TacticRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveTechniqueServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveTechniqueServiceImpl.java
new file mode 100644
index 0000000..6755165
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/RetrieveTechniqueServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.Repositories.TechniqueRepo;
+import uestc.zhanghanwen.ATTCK.POJOs.Technique;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * This is the service implementation class for {@link TechniqueRepo}.
+ * The return types are all {@code List}
+ *
+ * @see TechniqueRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class RetrieveTechniqueServiceImpl extends RetrieveServiceImplement {
+
+ @Autowired
+ public RetrieveTechniqueServiceImpl(TechniqueRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/package-info.java
new file mode 100644
index 0000000..c07d469
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/Implements/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The implementation of all services.
+ */
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.Implements;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/RetrieveService.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/RetrieveService.java
new file mode 100644
index 0000000..228c454
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/RetrieveService.java
@@ -0,0 +1,65 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices;
+
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+
+/**
+ * The interface for all Services inside.
+ * This is the interface oriented mode, that makes easier for {@link RetrieveServiceBundle}
+ * to manage all services.
+ *
+ * @see RetrieveServiceBundle
+ * @author zhanghanwen
+ * @version 1.0
+ */
+public interface RetrieveService {
+
+ /**
+ * Get the node by it's mitre id.
+ *
+ * @throws Exception if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository#findByMitreId} fails
+ * @param mitreId mitre id
+ * @return {@link ResultWrapper} of the queried result.
+ */
+ ResultWrapper findByMitreId(String mitreId) throws Exception;
+
+ /**
+ * Get the node by it's name.
+ *
+ * @throws Exception if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository#findByName} fails
+ * @param name name
+ * @return {@link ResultWrapper} of the queried result.
+ */
+ ResultWrapper findByName(String name) throws Exception;
+
+ /**
+ * Get all nodes by type, with page and size specified.
+ * if page is both -1, then return all results.
+ *
+ * @throws Exception if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository#findAll} fails
+ * @param type the specified type.
+ * @param page page, start from 0.
+ * @param size size, how many records in one page.
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ ResultWrapper findAll(String type, int page, int size) throws Exception;
+
+ /**
+ * Find all related nodes of one node.
+ *
+ * @throws Exception
+ * if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository#findRelatedByStartNodeMitreId} fails
+ * @param startNodeMitreId mitre id of the start node.
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ ResultWrapper findRelatedNodes(String startNodeMitreId) throws Exception;
+
+ /**
+ * Return the specified relationship name between two given nodes.
+ *
+ * @throws Exception if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository#findRelationshipByMitreId} fails
+ * @param startNodeMitreId the mitre id of the start node.
+ * @param endNodeMitreId the mitre id of the end node.
+ * @return {@link ResultWrapper} containing the relationship name.
+ */
+ ResultWrapper findRelationship(String startNodeMitreId, String endNodeMitreId) throws Exception;
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/RetrieveServiceBundle.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/RetrieveServiceBundle.java
new file mode 100644
index 0000000..c2d44ce
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/RetrieveServiceBundle.java
@@ -0,0 +1,221 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.Implements.*;
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.ServiceInterface;
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.ServiceBundle;
+import uestc.zhanghanwen.ATTCK.Wrappers.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONArray;
+import java.util.Map.Entry;
+
+/**
+ * This is the consultation class for all POJO retrieve services.
+ * That all services are accessed by one single group of API provided by this class,
+ * that is, {@link RetrieveService}.
+ * For specifications of the interfaces, see {@link RetrieveServiceBundle#RetrieveServiceBundle}
+ *
+ * @see RetrieveService
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class RetrieveServiceBundle extends ServiceBundle {
+
+ /**
+ * {@link Autowired} of spring services listed below. The service implements are listed as below.
+ * The services are managed and accessed by a simple array of type {@link RetrieveService}.
+ *
+ * @param mitigationService {@link RetrieveMitigationServiceImpl}
+ * @param techniqueService {@link RetrieveTechniqueServiceImpl}
+ * @param softwareService {@link RetrieveSoftwareServiceImpl}
+ * @param tacticService {@link RetrieveTacticServiceImpl}
+ * @param matrixService {@link RetrieveMatrixServiceImpl}
+ * @param groupService {@link RetrieveGroupServiceImpl}
+ */
+ @Autowired
+ public RetrieveServiceBundle(
+ RetrieveMitigationServiceImpl mitigationService,
+ RetrieveTechniqueServiceImpl techniqueService,
+ RetrieveSoftwareServiceImpl softwareService,
+ RetrieveTacticServiceImpl tacticService,
+ RetrieveMatrixServiceImpl matrixService,
+ RetrieveGroupServiceImpl groupService
+ ) {
+ this.getServices().put("mitigation", mitigationService);
+ this.getServices().put("technique", techniqueService);
+ this.getServices().put("software", softwareService);
+ this.getServices().put("tactic", tacticService);
+ this.getServices().put("matrix", matrixService);
+ this.getServices().put("group", groupService);
+ }
+
+ /**
+ * Get the node by it's mitre id.
+ *
+ * @param query the {@link QueryWrapper} of wrapped query of mitre id.
+ * @return {@link ResponseWrapper} wrapped response
+ */
+ public ResponseWrapper findByName(QueryWrapper query) {
+
+ String name = query.getName();
+
+ ResponseWrapper response = new ResponseWrapper();
+
+ try {
+ for (Entry entry: this.getServices().entrySet()) {
+ response.addAll(((RetrieveService) entry.getValue()).findByName(name));
+ }
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ }
+ return response;
+ }
+
+ /**
+ * Get the node by it's name.
+ *
+ * @param query the {@link QueryWrapper} of wrapped query of name.
+ * @return {@link ResponseWrapper} wrapped response
+ */
+ public ResponseWrapper findByMitreId(QueryWrapper query) {
+
+ String mitreId = query.getMitreId();
+ String type = query.getType();
+ ResponseWrapper response = new ResponseWrapper();
+
+ RetrieveService service = (RetrieveService) this.getService(type);
+
+ if (service != null) {
+
+ try {
+ response.addAll(service.findByMitreId(mitreId));
+
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ }
+ } else {
+ response.addAll(ResultWrapper.wrongTypeResult(type));
+ }
+ return response;
+ }
+
+ /**
+ * Get all nodes by type, with page and size specified.
+ * if page and size are both -1, then return all results.
+ *
+ * @param query the {@link QueryWrapper} of wrapped query of type.
+ * @return {@link ResponseWrapper} wrapped response
+ */
+ public ResponseWrapper findAll(QueryWrapper query) {
+
+ String type = query.getType();
+ int page = query.getPage();
+ int size = query.getSize();
+ ResponseWrapper response = new ResponseWrapper();
+
+ RetrieveService service = (RetrieveService) this.getService(type);
+
+ if (service != null) {
+ try {
+ response.addAll(service.findAll(type, page, size));
+
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ }
+ } else {
+ response.addAll(ResultWrapper.wrongTypeResult(type));
+ }
+ return response;
+ }
+
+ /**
+ * Get all related nodes by mitre id.
+ *
+ * @param query the {@link QueryWrapper} of wrapped query of type.
+ * @return {@link ResponseWrapper} wrapped response
+ */
+ public ResponseWrapper findRelatedWithoutRelationshipName(QueryWrapper query) {
+
+ String miterId = query.getMitreId();
+
+ ResponseWrapper current = findByMitreId(query);
+
+ //if not found or error
+ if (current.getStatus() != ResponseWrapper.OK) {
+ return current;
+ }
+
+ ResponseWrapper response = new ResponseWrapper();
+
+ JSONArray result = new JSONArray();
+
+ JSONObject original = new JSONObject();
+ original.put("original", current.getResult().get(0));
+ result.add(0, original);
+
+ JSONObject ends = new JSONObject(1);
+ ends.put("related", new JSONArray());
+
+ result.add(1, ends);
+ response.setResult(result);
+
+ ResultWrapper relatedWrapper;
+ try {
+ relatedWrapper = ((RetrieveService) this.getService(query.getType()))
+ .findRelatedNodes(miterId);
+
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ return response;
+ }
+
+ if (relatedWrapper.getStatusCode() == ResultWrapper.NO_RECORD) {
+ response.setStatus(ResponseWrapper.NO_RECORD);
+ response.setDetail(relatedWrapper.getMsgSpec());
+ return response;
+ }
+
+ if (relatedWrapper.getStatusCode() != ResultWrapper.OK) {
+ response.setStatus(ResponseWrapper.REQUEST_ERROR);
+ response.setDetail(relatedWrapper.getMsgSpec());
+ return response;
+ }
+
+ ((JSONArray) ends.get("related")).addAll(relatedWrapper.getResult());
+ response.setStatus(ResponseWrapper.OK);
+ response.setDetail(relatedWrapper.getMsgSpec());
+
+ return response;
+ }
+
+ /**
+ * Get the specified relationship name between two given nodes.
+ *
+ * @param query the {@link QueryWrapper} of wrapped query of type.
+ * @return {@link ResponseWrapper} wrapped response
+ */
+ public ResponseWrapper findRelationship(QueryWrapper query) {
+
+ ResponseWrapper response = new ResponseWrapper();
+ String startNodeId = ((JSONObject) query.getNodes().get(0)).getString("mitre_id");
+ String endNodeId = ((JSONObject) query.getNodes().get(1)).getString("mitre_id");
+ String type = query.getType();
+
+ RetrieveService service = (RetrieveService) this.getService(type);
+
+ if (service != null) {
+ try {
+ response.addAll(service.findRelationship(startNodeId, endNodeId));
+
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ }
+ } else {
+ response.addAll(ResultWrapper.wrongTypeResult(type));
+ }
+
+ return response;
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/package-info.java
new file mode 100644
index 0000000..42c172f
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/RetrieveServices/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * The SpringBoot service for {@link uestc.zhanghanwen.ATTCK.RestWebControllers.RetrieveController}
+ * of different type {@link uestc.zhanghanwen.ATTCK.POJOs.GraphNode}
+ */
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/ServiceBundle.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/ServiceBundle.java
new file mode 100644
index 0000000..b5c9fdf
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/ServiceBundle.java
@@ -0,0 +1,82 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices;
+
+import org.springframework.stereotype.Service;
+import java.util.Hashtable;
+import java.util.Map;
+import lombok.Getter;
+
+/**
+ * The abstract class for service bundle.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Getter
+@Service
+public abstract class ServiceBundle {
+
+ /**
+ * The hashtable containing all services of different types in {@link uestc.zhanghanwen.ATTCK.POJOs}
+ */
+ final protected Hashtable services = new Hashtable<>(6);
+
+ /**
+ * Check if node exist
+ *
+ * @param mitreId mitre id to check
+ * @return ture if exists
+ */
+ protected Boolean isNodeExist(String mitreId) {
+ for (Map.Entry entry: services.entrySet()) {
+ try {
+ if (entry.getValue().isNodeExist(mitreId)) {
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check for two nodes' existence
+ *
+ * @param startNodeMitreId node 1
+ * @param endNodeMitreId node 2
+ * @return true if both exist
+ */
+ protected Boolean isStartAndEndNodeExists(String startNodeMitreId, String endNodeMitreId) {
+ return this.isNodeExist(startNodeMitreId) && this.isNodeExist(endNodeMitreId);
+ }
+
+ /**
+ * Check if relationship exist
+ *
+ * @param startNodeMitreId start node mitre id
+ * @param endNodeMitreId end node mitre id
+ * @return true if exists
+ */
+ protected Boolean isRelationshipExist(String startNodeMitreId, String endNodeMitreId) {
+ for (Map.Entry entry : services.entrySet()) {
+ try {
+ if (entry.getValue().isRelationshipExist(startNodeMitreId, endNodeMitreId)) {
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * get the service of a specific type
+ *
+ * @param type one of {@link uestc.zhanghanwen.ATTCK.POJOs.GraphNode}
+ * @return null if type not exist
+ */
+ protected ServiceInterface getService(String type) {
+ return this.services.get(type);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/ServiceInterface.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/ServiceInterface.java
new file mode 100644
index 0000000..c8ef64a
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/ServiceInterface.java
@@ -0,0 +1,28 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices;
+
+/**
+ * The interface for {@link ServiceBundle} to call and two utility methods.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+public interface ServiceInterface {
+ /**
+ * Check if node exist
+ *
+ * @throws Exception if fails
+ * @param mitreId mitre id to check
+ * @return ture if exists
+ */
+ Boolean isNodeExist(String mitreId) throws Exception;
+
+ /**
+ * Check if relationship exist
+ *
+ * @throws Exception if fails
+ * @param startNodeMitreId start node mitre id
+ * @param endNodeMitreId end node mitre id
+ * @return true if exists
+ */
+ Boolean isRelationshipExist(String startNodeMitreId, String endNodeMitreId) throws Exception;
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateGroupServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateGroupServiceImpl.java
new file mode 100644
index 0000000..72d8748
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateGroupServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Group;
+import uestc.zhanghanwen.ATTCK.Repositories.GroupRepo;
+
+/**
+ * This is the service implementation class for {@link GroupRepo}.
+ * The return types are all {@code List}
+ *
+ * @see GroupRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class UpdateGroupServiceImpl extends UpdateServiceImplement {
+
+ @Autowired
+ public UpdateGroupServiceImpl(GroupRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateMatrixServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateMatrixServiceImpl.java
new file mode 100644
index 0000000..6252821
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateMatrixServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Matrix;
+import uestc.zhanghanwen.ATTCK.Repositories.MatrixRepo;
+
+/**
+ * This is the service implementation class for {@link MatrixRepo}.
+ * The return types are all {@code List}
+ *
+ * @see MatrixRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class UpdateMatrixServiceImpl extends UpdateServiceImplement {
+
+ @Autowired
+ public UpdateMatrixServiceImpl(MatrixRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateMitigationServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateMitigationServiceImpl.java
new file mode 100644
index 0000000..c57414a
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateMitigationServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Mitigation;
+import uestc.zhanghanwen.ATTCK.Repositories.MitigationRepo;
+
+/**
+ * This is the service implementation class for {@link MitigationRepo}.
+ * The return types are all {@code List}
+ *
+ * @see MitigationRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class UpdateMitigationServiceImpl extends UpdateServiceImplement {
+
+ @Autowired
+ public UpdateMitigationServiceImpl(MitigationRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateServiceImplement.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateServiceImplement.java
new file mode 100644
index 0000000..85cd7d5
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateServiceImplement.java
@@ -0,0 +1,37 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.Implements;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.UpdateService;
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.ATTCKService;
+import uestc.zhanghanwen.ATTCK.Repositories.NodeRepository;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import org.springframework.transaction.annotation.Transactional;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONArray;
+
+/**
+ * This class has the implementation of methods in {@link UpdateService} used in
+ * {@link uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.UpdateServiceBundle}
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+abstract class UpdateServiceImplement>
+ extends ATTCKService
+ implements UpdateService {
+
+ /**
+ * update one node.
+ *
+ * @param node the node to be saved.
+ * @return {@link JSONArray} of all queried results.
+ * @throws Exception if {@link NodeRepository#save} fails or the mitre id of the saved node is not matched
+ * as the expected input, then rollback.
+ * @see ATTCKService#save
+ */
+ @Override
+ @Transactional
+ public ResultWrapper mergeOneNode(JSONObject node) throws Exception {
+ return this.save(node);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateSoftwareServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateSoftwareServiceImpl.java
new file mode 100644
index 0000000..7e992f3
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateSoftwareServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Software;
+import uestc.zhanghanwen.ATTCK.Repositories.SoftwareRepo;
+
+/**
+ * This is the service implementation class for {@link SoftwareRepo}.
+ * The return types are all {@code List}
+ *
+ * @see SoftwareRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class UpdateSoftwareServiceImpl extends UpdateServiceImplement {
+
+ @Autowired
+ public UpdateSoftwareServiceImpl(SoftwareRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateTacticServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateTacticServiceImpl.java
new file mode 100644
index 0000000..3b235ea
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateTacticServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Tactic;
+import uestc.zhanghanwen.ATTCK.Repositories.TacticRepo;
+
+/**
+ * This is the service implementation class for {@link TacticRepo}.
+ * The return types are all {@code List}
+ *
+ * @see TacticRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class UpdateTacticServiceImpl extends UpdateServiceImplement {
+
+ @Autowired
+ public UpdateTacticServiceImpl(TacticRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateTechniqueServiceImpl.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateTechniqueServiceImpl.java
new file mode 100644
index 0000000..57011af
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/UpdateTechniqueServiceImpl.java
@@ -0,0 +1,23 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.Implements;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import uestc.zhanghanwen.ATTCK.POJOs.Technique;
+import uestc.zhanghanwen.ATTCK.Repositories.TechniqueRepo;
+
+/**
+ * This is the service implementation class for {@link TechniqueRepo}.
+ * The return types are all {@code List}
+ *
+ * @see TechniqueRepo
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Service
+public class UpdateTechniqueServiceImpl extends UpdateServiceImplement {
+
+ @Autowired
+ public UpdateTechniqueServiceImpl(TechniqueRepo repository) {
+ this.setRepo(repository);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/package-info.java
new file mode 100644
index 0000000..b47cea5
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/Implements/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The implementation of all services.
+ */
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.Implements;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/UpdateService.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/UpdateService.java
new file mode 100644
index 0000000..6b81699
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/UpdateService.java
@@ -0,0 +1,24 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices;
+
+import uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper;
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * The interface for all Services inside.
+ * This is the interface oriented mode, that makes easier for {@link UpdateServiceBundle} to manage all services.
+ *
+ * @see UpdateServiceBundle
+ * @author zhanghanwen
+ * @version 1.0
+ */
+public interface UpdateService {
+
+ /**
+ * update one node.
+ *
+ * @throws Exception if {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository#save} fails
+ * @param node in format of {@link JSONObject}
+ * @return {@link ResultWrapper} of all queried results.
+ */
+ ResultWrapper mergeOneNode(JSONObject node) throws Exception;
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/UpdateServiceBundle.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/UpdateServiceBundle.java
new file mode 100644
index 0000000..ab5807c
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/UpdateServiceBundle.java
@@ -0,0 +1,71 @@
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.Implements.*;
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.ServiceBundle;
+import uestc.zhanghanwen.ATTCK.Wrappers.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * This is the consultation class for all POJO services.
+ * That all services are accessed by one single group of API provided by this class,
+ * that is, {@link UpdateService}.
+ *
+ * @see UpdateService
+ * @author zhanghanwen
+ * @version 1.0
+ */@Service
+public class UpdateServiceBundle extends ServiceBundle {
+
+ /**
+ * Autowire({@link Autowired}) of spring services listed below. The service implements are listed as below.
+ * The services are managed and accessed by a simple array of type {@link UpdateService}.
+ *
+ * @param mitigationService {@link UpdateMitigationServiceImpl}
+ * @param techniqueService {@link UpdateTechniqueServiceImpl}
+ * @param softwareService {@link UpdateSoftwareServiceImpl}
+ * @param tacticService {@link UpdateTacticServiceImpl}
+ * @param matrixService {@link UpdateMatrixServiceImpl}
+ * @param groupService {@link UpdateGroupServiceImpl}
+ */
+ @Autowired
+ public UpdateServiceBundle(
+ UpdateMitigationServiceImpl mitigationService,
+ UpdateTechniqueServiceImpl techniqueService,
+ UpdateSoftwareServiceImpl softwareService,
+ UpdateTacticServiceImpl tacticService,
+ UpdateMatrixServiceImpl matrixService,
+ UpdateGroupServiceImpl groupService
+ ) {
+ this.getServices().put("mitigation", mitigationService);
+ this.getServices().put("technique", techniqueService);
+ this.getServices().put("software", softwareService);
+ this.getServices().put("tactic", tacticService);
+ this.getServices().put("matrix", matrixService);
+ this.getServices().put("group", groupService);
+ }
+
+ public ResponseWrapper mergeNode(QueryWrapper query) {
+
+ JSONObject node = query.getNodes().getJSONObject(0);
+ String mitreId = node.getString("mitre_id");
+ String type = node.getString("type");
+
+ ResponseWrapper response = new ResponseWrapper();
+
+ if (!this.isNodeExist(mitreId)) {
+ response.setStatus(ResponseWrapper.NO_RECORD);
+ response.setMsg(ResponseWrapper.NO_RECORD_MSG);
+ response.setDetail("the start node of mitre id '" + mitreId + "' is not found.");
+ return response;
+ }
+
+ try {
+ response.addAll(((UpdateService) services.get(type)).mergeOneNode(node));
+ } catch (Exception e) {
+ response.addAll(ResultWrapper.errorResult(e));
+ }
+ return response;
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/package-info.java
new file mode 100644
index 0000000..b23c0bc
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/GraphCRUDServices/UpdateServices/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * The SpringBoot service for {@link uestc.zhanghanwen.ATTCK.RestWebControllers.UpdateController}
+ * of different type {@link uestc.zhanghanwen.ATTCK.POJOs.GraphNode}
+ */
+package uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/GraphNode.java b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/GraphNode.java
new file mode 100644
index 0000000..6b4d29e
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/GraphNode.java
@@ -0,0 +1,163 @@
+package uestc.zhanghanwen.ATTCK.POJOs;
+
+import org.neo4j.ogm.annotation.Property;
+import org.neo4j.ogm.annotation.Id;
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.JSON;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import java.util.ArrayList;
+import lombok.NoArgsConstructor;
+import lombok.Data;
+
+/**
+ * This is the super class for all mitre GraphNode objects.
+ * It also supports serialize and deserialize for both Neo4j database and {@code JSON} {@link String}
+ * via {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository} and {@link JSON}.
+ * For details of the data inside the objects,
+ * please see mitre object spec
+ *
+ * @see uestc.zhanghanwen.ATTCK.Repositories.NodeRepository
+ * @see JSON
+ * @version 1.0
+ * @author zhanghanwen
+ */
+@Data
+@NoArgsConstructor
+public abstract class GraphNode {
+
+ /**
+ * The mitre id of the object as the key.
+ */
+ @Id
+ @JSONField(name = "mitre_id")
+ @Property(name = "mitre_id")
+ private String mitreId;
+
+ /**
+ * The name of the object.
+ */
+ @JSONField(name = "name")
+ @Property(name = "name")
+ private String name;
+
+ /**
+ * The description of the object.
+ */
+ @JSONField(name = "description")
+ @Property(name = "description")
+ private String description;
+
+ /**
+ * The platform of the object.
+ */
+ @JSONField(name = "platform")
+ @Property(name = "platform")
+ private ArrayList platform;
+
+ /**
+ * The required permission of the object.
+ */
+ @JSONField(name = "permission_required")
+ @Property(name = "permission_required")
+ private ArrayList permissionRequired;
+
+ /**
+ * The permission level that effects the attack.
+ */
+ @JSONField(name = "effective_permission")
+ @Property(name = "effective_permission")
+ private ArrayList effectivePermission;
+
+ /**
+ * If the attack requires network.
+ */
+ @JSONField(name = "network")
+ @Property(name = "network")
+ private Boolean networkRequired;
+
+ /**
+ * If remote operations required.
+ */
+ @JSONField(name = "remote")
+ @Property(name = "remote")
+ private Boolean remoteRequired;
+
+ /**
+ * The requirements of the object.
+ */
+ @JSONField(name = "requirements")
+ @Property(name = "requirements")
+ private String requirements;
+
+ /**
+ * Serialize the object into {@link String} in the format of {@code JSON}
+ *
+ * @return {@code JSON string}
+ */
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+
+ /**
+ * Determines if two mitre objects are equal.
+ * Since the mitre id is the key in database, it only compares if the {@link GraphNode#mitreId} is the same.
+ *
+ * @param obj another {@link GraphNode} to be compared.
+ * @return {@code true} if the {@link GraphNode#mitreId} is the same, {@code false} otherwise.
+ */
+ @Override
+ @Contract(pure = true)
+ public boolean equals(@NotNull Object obj) {
+ if (obj.getClass() == this.getClass()) {
+ if (this.getMitreId() != null && ((GraphNode) obj).getMitreId() != null) {
+ return this.getMitreId().equals(((GraphNode) obj).getMitreId());
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ * Tool method that infers the type from the mitre id.
+ * Note that only legal input of a mitre id will return a correct result.
+ * The method itself doesn't check the correctness of the input, it must be designed when the method is called.
+ *
+ * @param mitreId the mitre id to be inferred.
+ * @return The inferred type.
+ */
+ public static String getTypeFromMitreId(@NotNull String mitreId) {
+
+ switch (mitreId.charAt(0)) {
+ case 'S':
+ return "software";
+
+ case 'G':
+ return "group";
+
+ case 'T':
+ char second = mitreId.charAt(1);
+ if (second == 'A') {
+ return "tactic";
+ } else {
+ return "technique";
+ }
+
+ case 'M':
+ second = mitreId.charAt(1);
+ if (second == 'T') {
+ return "matrix";
+ } else {
+ return "mitigation";
+ }
+
+ default:
+ return "matrix";
+ }
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Group.java b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Group.java
new file mode 100644
index 0000000..35a668f
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Group.java
@@ -0,0 +1,16 @@
+package uestc.zhanghanwen.ATTCK.POJOs;
+
+import org.neo4j.ogm.annotation.NodeEntity;
+import lombok.NoArgsConstructor;
+
+/**
+ * This is the class Group mitre GraphNode objects.
+ * The params inside the Group is the same from its super.
+ *
+ * @see GraphNode
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@NodeEntity(label = "group")
+@NoArgsConstructor
+public class Group extends GraphNode {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Matrix.java b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Matrix.java
new file mode 100644
index 0000000..febd7cb
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Matrix.java
@@ -0,0 +1,16 @@
+package uestc.zhanghanwen.ATTCK.POJOs;
+
+import org.neo4j.ogm.annotation.NodeEntity;
+import lombok.NoArgsConstructor;
+
+/**
+ * This is the class Matrix mitre GraphNode objects.
+ * The params inside the Matrix is the same from its super.
+ *
+ * @see GraphNode
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@NodeEntity(label = "matrix")
+@NoArgsConstructor
+public class Matrix extends GraphNode {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Mitigation.java b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Mitigation.java
new file mode 100644
index 0000000..56869ce
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Mitigation.java
@@ -0,0 +1,16 @@
+package uestc.zhanghanwen.ATTCK.POJOs;
+
+import org.neo4j.ogm.annotation.NodeEntity;
+import lombok.NoArgsConstructor;
+
+/**
+ * This is the class Mitigation mitre GraphNode objects.
+ * The params inside the Mitigation is the same from its super.
+ *
+ * @author zhanghanwen
+ * @see GraphNode
+ * @version 1.0
+ */
+@NodeEntity(label = "mitigation")
+@NoArgsConstructor
+public class Mitigation extends GraphNode {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Software.java b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Software.java
new file mode 100644
index 0000000..427a478
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Software.java
@@ -0,0 +1,16 @@
+package uestc.zhanghanwen.ATTCK.POJOs;
+
+import org.neo4j.ogm.annotation.NodeEntity;
+import lombok.NoArgsConstructor;
+
+/**
+ * This is the class Software mitre GraphNode objects.
+ * The params inside the Software is the same from its super.
+ *
+ * @see GraphNode
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@NodeEntity(label = "software")
+@NoArgsConstructor
+public class Software extends GraphNode {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Tactic.java b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Tactic.java
new file mode 100644
index 0000000..0e420f0
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Tactic.java
@@ -0,0 +1,16 @@
+package uestc.zhanghanwen.ATTCK.POJOs;
+
+import org.neo4j.ogm.annotation.NodeEntity;
+import lombok.NoArgsConstructor;
+
+/**
+ * This is the class Tactic mitre GraphNode objects.
+ * The params inside the Tactic is the same from its super.
+ *
+ * @see GraphNode
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@NodeEntity(label = "tactic")
+@NoArgsConstructor
+public class Tactic extends GraphNode {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Technique.java b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Technique.java
new file mode 100644
index 0000000..e73b9f2
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/Technique.java
@@ -0,0 +1,16 @@
+package uestc.zhanghanwen.ATTCK.POJOs;
+
+import org.neo4j.ogm.annotation.NodeEntity;
+import lombok.NoArgsConstructor;
+
+/**
+ * This is the class Technique mitre GraphNode objects.
+ * Apart from super, it has more params.
+ *
+ * @see GraphNode
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@NodeEntity(label = "technique")
+@NoArgsConstructor
+public class Technique extends GraphNode {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/package-info.java
new file mode 100644
index 0000000..717a834
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/POJOs/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Plain Old Java Objects for nodes.
+ * The abstract class is {@link uestc.zhanghanwen.ATTCK.POJOs.GraphNode},
+ * others are extended from it.
+ */
+package uestc.zhanghanwen.ATTCK.POJOs;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/GroupRepo.java b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/GroupRepo.java
new file mode 100644
index 0000000..a6b8efd
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/GroupRepo.java
@@ -0,0 +1,17 @@
+package uestc.zhanghanwen.ATTCK.Repositories;
+
+import uestc.zhanghanwen.ATTCK.POJOs.Group;
+import org.springframework.stereotype.Repository;
+
+/**
+ * The DAO {@link NodeRepository} for POJO {@link Group}.
+ * That all the query methods are from this class.
+ *
+ * @see uestc.zhanghanwen.ATTCK.POJOs.GraphNode
+ * @see NodeRepository
+ * @see Group
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Repository
+public interface GroupRepo extends NodeRepository {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/MatrixRepo.java b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/MatrixRepo.java
new file mode 100644
index 0000000..204e880
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/MatrixRepo.java
@@ -0,0 +1,17 @@
+package uestc.zhanghanwen.ATTCK.Repositories;
+
+import uestc.zhanghanwen.ATTCK.POJOs.Matrix;
+import org.springframework.stereotype.Repository;
+
+/**
+ * The DAO {@link NodeRepository} for POJO {@link Matrix}.
+ * That all the query methods are from this class.
+ *
+ * @see uestc.zhanghanwen.ATTCK.POJOs.GraphNode
+ * @see NodeRepository
+ * @see Matrix
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Repository
+public interface MatrixRepo extends NodeRepository {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/MitigationRepo.java b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/MitigationRepo.java
new file mode 100644
index 0000000..d83b3c4
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/MitigationRepo.java
@@ -0,0 +1,17 @@
+package uestc.zhanghanwen.ATTCK.Repositories;
+
+import uestc.zhanghanwen.ATTCK.POJOs.Mitigation;
+import org.springframework.stereotype.Repository;
+
+/**
+ * The DAO {@link NodeRepository} for POJO {@link Mitigation}.
+ * That all the query methods are from this class.
+ *
+ * @see uestc.zhanghanwen.ATTCK.POJOs.GraphNode
+ * @see NodeRepository
+ * @see Mitigation
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Repository
+public interface MitigationRepo extends NodeRepository {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/NodeRepository.java b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/NodeRepository.java
new file mode 100644
index 0000000..b5c07e7
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/NodeRepository.java
@@ -0,0 +1,136 @@
+package uestc.zhanghanwen.ATTCK.Repositories;
+
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import org.springframework.data.neo4j.repository.Neo4jRepository;
+import org.springframework.data.neo4j.annotation.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+import java.util.List;
+
+/**
+ * The {@link Neo4jRepository} interface of cypher queries.
+ * For different types of node, each one can inherit to create it's own repository.
+ *
+ * @see Neo4jRepository
+ * @see GraphNode
+ * @author zhanghanwen
+ * @version 1.0
+ * @param inheritance of {@link GraphNode}
+ */
+@Repository
+public interface NodeRepository extends Neo4jRepository {
+
+ /**
+ * query object by name from database
+ *
+ * @param name name
+ * @return List of queried objects
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m) WHERE m.name=$name RETURN m;")
+ List findByName(@Param("name") String name) throws Exception;
+
+ /**
+ * query object by id from database
+ *
+ * @param id id
+ * @return List of queried objects
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m) WHERE m.mitre_id=$id RETURN m;")
+ List findByMitreId(@Param("id") String id) throws Exception;
+
+ /**
+ * query all related objects from database
+ *
+ * @param mitreId id
+ * @param instance of {@link GraphNode}
+ * @return List of queried objects
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m)-[r]->(n) WHERE m.mitre_id=$m1 RETURN n;")
+ List findRelatedByStartNodeMitreId(@Param("m1") String mitreId) throws Exception;
+
+ /**
+ * query relationship between two objects by id from database
+ *
+ * @param mitreId1 start node
+ * @param mitreId2 end node
+ * @return List of queried objects
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m)-[r]->(n) WHERE m.mitre_id=$m1 AND n.mitre_id=$m2 RETURN type(r);")
+ String findRelationshipByMitreId(@Param("m1") String mitreId1, @Param("m2") String mitreId2) throws Exception;
+
+ /**
+ * create relationship 'contains' between two objects by id into database
+ *
+ * @param mitreId1 start node
+ * @param mitreId2 end node
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m), (n) WHERE m.mitre_id=$m1 AND n.mitre_id=$m2 MERGE (m)-[r:contains]->(n) MERGE (n)-[re:in]->(m);")
+ void createContainsRelationshipByMitreId(@Param("m1") String mitreId1, @Param("m2") String mitreId2)
+ throws Exception;
+ /**
+ * create relationship 'in' between two objects by id into database
+ *
+ * @param mitreId1 start node
+ * @param mitreId2 end node
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m), (n) WHERE m.mitre_id=$m1 AND n.mitre_id=$m2 MERGE (m)-[r:in]->(n) MERGE (n)-[re:contains]->(m);")
+ void createInRelationshipByMitreId(@Param("m1") String mitreId1, @Param("m2") String mitreId2) throws Exception;
+
+ /**
+ * create relationship 'uses' between two objects by id into database
+ *
+ * @param mitreId1 start node
+ * @param mitreId2 end node
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m), (n) WHERE m.mitre_id=$m1 AND n.mitre_id=$m2 MERGE (m)-[r:uses]->(n) " +
+ "MERGE (n)-[re:`is used by`]->(m);")
+ void createUsesRelationshipByMitreId(@Param("m1") String mitreId1, @Param("m2") String mitreId2) throws Exception;
+
+ /**
+ * create relationship 'is used by' between two objects by id into database
+ *
+ * @param mitreId1 start node
+ * @param mitreId2 end node
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m), (n) WHERE m.mitre_id=$m1 AND n.mitre_id=$m2 " +
+ "MERGE (m)-[r:`is used by`]->(n) MERGE (n)-[re:`uses`]->(m);")
+ void createUsedByRelationshipByMitreId(@Param("m1") String mitreId1, @Param("m2") String mitreId2)
+ throws Exception;
+
+ /**
+ * delete an object by id from database
+ *
+ * @param mitreId id
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m) WHERE m.mitre_id=$m1 DELETE m;")
+ void deleteByMitreId(@Param("m1") String mitreId) throws Exception;
+
+ /**
+ * delete all relationships of an object by id from database
+ *
+ * @param mitreId id
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m)-[r]->(n), (n)-[re]->(m) WHERE m.mitre_id=$m1 DELETE r, re;")
+ void deleteRelationships(@Param("m1") String mitreId) throws Exception;
+
+ /**
+ * delete relationship between two objects by id from database
+ *
+ * @param mitreId1 start node
+ * @param mitreId2 end node
+ * @throws Exception if fails
+ */
+ @Query("MATCH (m)-[r]->(n), (n)-[re]->(m) WHERE m.mitre_id=$m1 AND n.mitre_id=$m2 DELETE r, re;")
+ void deleteRelationshipByStartNodeMitreId(@Param("m1") String mitreId1, @Param("m2") String mitreId2)
+ throws Exception;
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/SoftwareRepo.java b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/SoftwareRepo.java
new file mode 100644
index 0000000..6a14ea1
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/SoftwareRepo.java
@@ -0,0 +1,17 @@
+package uestc.zhanghanwen.ATTCK.Repositories;
+
+import uestc.zhanghanwen.ATTCK.POJOs.Software;
+import org.springframework.stereotype.Repository;
+
+/**
+ * The DAO {@link NodeRepository} for POJO {@link Software}.
+ * That all the query methods are from this class.
+ *
+ * @see uestc.zhanghanwen.ATTCK.POJOs.GraphNode
+ * @see NodeRepository
+ * @see Software
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Repository
+public interface SoftwareRepo extends NodeRepository {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/TacticRepo.java b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/TacticRepo.java
new file mode 100644
index 0000000..5120ab5
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/TacticRepo.java
@@ -0,0 +1,17 @@
+package uestc.zhanghanwen.ATTCK.Repositories;
+
+import uestc.zhanghanwen.ATTCK.POJOs.Tactic;
+import org.springframework.stereotype.Repository;
+
+/**
+ * The DAO {@link NodeRepository} for POJO {@link Tactic}.
+ * That all the query methods are from this class.
+ *
+ * @see uestc.zhanghanwen.ATTCK.POJOs.GraphNode
+ * @see NodeRepository
+ * @see Tactic
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Repository
+public interface TacticRepo extends NodeRepository {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/TechniqueRepo.java b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/TechniqueRepo.java
new file mode 100644
index 0000000..ed7b021
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/TechniqueRepo.java
@@ -0,0 +1,17 @@
+package uestc.zhanghanwen.ATTCK.Repositories;
+
+import uestc.zhanghanwen.ATTCK.POJOs.Technique;
+import org.springframework.stereotype.Repository;
+
+/**
+ * The DAO {@link NodeRepository} for POJO {@link Technique}.
+ * That all the query methods are from this class.
+ *
+ * @see uestc.zhanghanwen.ATTCK.POJOs.GraphNode
+ * @see NodeRepository
+ * @see Technique
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Repository
+public interface TechniqueRepo extends NodeRepository {}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/package-info.java
new file mode 100644
index 0000000..e2f1be2
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Repositories/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Collections of all {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository}
+ * of different type {@link uestc.zhanghanwen.ATTCK.POJOs.GraphNode}
+ */
+package uestc.zhanghanwen.ATTCK.Repositories;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/CreateController.java b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/CreateController.java
new file mode 100644
index 0000000..3d9cb9a
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/CreateController.java
@@ -0,0 +1,93 @@
+package uestc.zhanghanwen.ATTCK.RestWebControllers;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.CreateServices.CreateServiceBundle;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResponseWrapper;
+import uestc.zhanghanwen.ATTCK.Wrappers.QueryWrapper;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.jetbrains.annotations.Contract;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSON;
+import lombok.Data;
+
+/**
+ * The RESTful controller class for all creating queries.
+ * The root URL path for this controller is {@code domain-name/create/}.
+ * The services are {@link CreateController#createNode} and {@link CreateController#createRelationship}.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Data
+@RestController
+@RequestMapping(value = "/create")
+public class CreateController {
+
+ CreateServiceBundle service;
+
+ @Contract(pure = true)
+ public CreateController(CreateServiceBundle service) {
+ this.setService(service);
+ }
+
+ /**
+ * Create a node into the database.
+ *
+ * @param value the object id to delete
+ * @return true or false
+ */
+ @RequestMapping(value = "/node", method = {RequestMethod.GET, RequestMethod.POST})
+ public String createNode(@RequestParam(value = "value") String value) {
+
+ JSONObject node = JSON.parseObject(value);
+ String type = node.getString("type");
+ String mitreId = node.getString("mitre_id");
+ String name = node.getString("name");
+
+ if (type == null || mitreId == null || name == null) {
+ return ResponseWrapper.paramErrorResponseFactory(
+ "key \"type\", \"mitreId\" and \"name\" must be specified in \"value\", " +
+ "got: type: " + type +
+ ", mitreId: " + mitreId +
+ ", name: " + name
+ ).toString();
+ }
+
+ JSONArray nodes = new JSONArray();
+ nodes.add(0, node);
+
+ QueryWrapper query = new QueryWrapper();
+ query.setType(type);
+ query.setNodes(nodes);
+
+ ResponseWrapper response = this.getService().createNode(query);
+ return response.toString();
+ }
+
+ /**
+ * Create a relationship between two nodes.
+ *
+ * @param startNodeMitreId s
+ * @param endNodeMitreId e
+ * @param relationship r
+ * @return string
+ */
+ @RequestMapping(value = "/relationship", method = {RequestMethod.GET, RequestMethod.POST})
+ public String createRelationship( @RequestParam(value = "start_id") String startNodeMitreId,
+ @RequestParam(value = "end_id") String endNodeMitreId,
+ @RequestParam String relationship
+ ) {
+
+ if (startNodeMitreId == null && endNodeMitreId == null) {
+ return ResponseWrapper.paramErrorResponseFactory("required: \"id\", found: none").toString();
+ }
+
+ QueryWrapper query = QueryWrapper.relationshipQueryFactory(startNodeMitreId, endNodeMitreId, relationship);
+ ResponseWrapper response = this.getService().createRelationship(query);
+
+ return response.toString();
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/DeleteController.java b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/DeleteController.java
new file mode 100644
index 0000000..08c8a79
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/DeleteController.java
@@ -0,0 +1,76 @@
+package uestc.zhanghanwen.ATTCK.RestWebControllers;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.DeleteServices.DeleteServiceBundle;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResponseWrapper;
+import uestc.zhanghanwen.ATTCK.Wrappers.QueryWrapper;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.jetbrains.annotations.Contract;
+import lombok.Data;
+
+/**
+ * The RESTful controller class for all creating queries.
+ * The root URL path for this controller is {@code domain-name/create/}.
+ * The services are {@link DeleteController#deleteObjectAndRelationship}
+ * and {@link DeleteController#deleteRelationship}.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Data
+@RestController
+@RequestMapping(value = "/delete")
+public class DeleteController {
+
+ DeleteServiceBundle service;
+
+ @Contract(pure = true)
+ public DeleteController(DeleteServiceBundle service) {
+ this.setService(service);
+ }
+
+ /**
+ * Delete an object and all its relationships.
+ *
+ * @param id the object id to delete
+ * @return true or false
+ */
+ @RequestMapping(value = "/node", method = {RequestMethod.GET, RequestMethod.POST})
+ public String deleteObjectAndRelationship(@RequestParam(value = "id") String id) {
+
+ if (id == null) {
+ return ResponseWrapper.paramErrorResponseFactory("required: \"id\", found: none").toString();
+ }
+
+ QueryWrapper query = new QueryWrapper();
+ query.setMitreId(id);
+
+ ResponseWrapper response = this.getService().deleteNode(query);
+ return response.toString();
+ }
+
+ /**
+ * delete the bi-directional relationship between two nodes
+ *
+ * @param startNodeMitreId the object id to delete
+ * @param endNodeMitreId the object id to delete
+ * @return true or false
+ */
+ @RequestMapping(value = "/relationship", method = {RequestMethod.GET, RequestMethod.POST})
+ public String deleteRelationship(
+ @RequestParam(value = "start_id") String startNodeMitreId,
+ @RequestParam(value = "end_id") String endNodeMitreId
+ ) {
+
+ if (startNodeMitreId == null || endNodeMitreId == null) {
+ return ResponseWrapper.paramErrorResponseFactory("Required both 'start_id' and 'end_id'.").toString();
+ }
+
+ QueryWrapper query = QueryWrapper.relationshipQueryFactory(startNodeMitreId, endNodeMitreId, null);
+ ResponseWrapper response = this.getService().deleteRelationship(query);
+
+ return response.toString();
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/RetrieveController.java b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/RetrieveController.java
new file mode 100644
index 0000000..9375605
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/RetrieveController.java
@@ -0,0 +1,185 @@
+package uestc.zhanghanwen.ATTCK.RestWebControllers;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.RetrieveServices.RetrieveServiceBundle;
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResponseWrapper;
+import uestc.zhanghanwen.ATTCK.Wrappers.QueryWrapper;
+import org.springframework.web.bind.annotation.*;
+import org.jetbrains.annotations.Contract;
+import lombok.Data;
+
+/**
+ * The RESTful controller class for all retrieving queries.
+ * The root URL path for this controller is {@code domain-name/query/}.
+ * The services are {@link RetrieveController#queryObject}, {@link RetrieveController#queryType},
+ * {@link RetrieveController#queryObjectByMitreId} and {@link RetrieveController#queryRelatedByStartNodeMitreId}.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Data
+@RestController
+@RequestMapping(value = "/query")
+public class RetrieveController {
+
+ /**
+ * The bundle of services of different node types.
+ * @see RetrieveServiceBundle
+ */
+ RetrieveServiceBundle service;
+
+ @Contract(pure = true)
+ public RetrieveController(RetrieveServiceBundle service) {
+ this.setService(service);
+ }
+
+ /**
+ * Query the mitre object by mitre id or name.
+ * The URL is {@code domain-name/query/}
+ * Can be accessed by both {@code GET} and {@code POST} method.
+ * the request parameter is {@code id} or {@code name}
+ * if both are provided, only id will be queried.
+ *
+ * @param name the name of the object to be queried.
+ * @param id the mitre id to be queried.
+ * @return the mitre object in JSON format.
+ */
+ @RequestMapping(value = "", method={RequestMethod.GET, RequestMethod.POST})
+ public String queryObject(
+ @RequestParam(required = false) String name,
+ @RequestParam(required = false) String id
+ ) {
+
+ if (id != null) {
+ // query by id, redirect to method RetrieveController#queryObjectByMitreId
+ return this.queryObjectByMitreId(id);
+ }
+
+ if(name == null) {
+ return ResponseWrapper.paramErrorResponseFactory("required: \"name\" or \"id\", found: none").toString();
+ }
+
+ //query by name
+ QueryWrapper query = new QueryWrapper();
+ query.setName(name);
+
+ ResponseWrapper response = this.getService().findByName(query);
+ return response.toString();
+ }
+
+ /**
+ * Query the mitre object by mitre.
+ * The URL is {@code domain-name/query/{SOME_ID}/}
+ * Can be accessed by both {@code GET} and {@code POST} method.
+ *
+ * @param id the mitre_id of the object to be queried.
+ * @return the mitre object in JSON format.
+ */
+ @RequestMapping(value = "/{id}", method={RequestMethod.GET, RequestMethod.POST})
+ public String queryObjectByMitreId(@PathVariable String id) {
+
+ QueryWrapper query = new QueryWrapper();
+ query.setMitreId(id);
+
+ ResponseWrapper response = this.getService().findByMitreId(query);
+ return response.toString();
+ }
+
+
+ /**
+ * Query the mitre object by type.
+ * The URL is {@code domain-name/query/type/{SOME_TYPE}}
+ * Can be accessed by both {@code GET} and {@code POST} method.
+ * The request parameter is {@code type} {@code get_all} (optional) and {@code page}
+ * {@code get_all} is default {@code false} and will get a page of 20 records each time.
+ * When {@code get_all} is {@code false} and {@code page} is not specified, the default page is 0.
+ *
+ * @param isGetAll whether get all objects or only one page, default false.
+ * @param type the mitre_id of the object to be queried.
+ * @param page the page number to get, default 0.
+ * @param size the size of one page, default 20.
+ * @return the mitre object in JSON format.
+ */
+ @RequestMapping(value = "/type/{type}", method={RequestMethod.GET, RequestMethod.POST})
+ public String queryType(@PathVariable String type,
+ @RequestParam(value = "get_all", defaultValue = "false", required = false) boolean isGetAll,
+ @RequestParam(defaultValue = "0", required = false) int page,
+ @RequestParam(defaultValue = "20", required = false) int size) {
+
+ QueryWrapper query = new QueryWrapper();
+ query.setType(type);
+
+ if (isGetAll) {
+ query.setPage(-1);
+ query.setSize(-1);
+
+ } else {
+ if (page >= 0) {
+ query.setPage(page);
+ } else {
+ return ResponseWrapper.paramErrorResponseFactory("page must be no smaller than 0, got " + page)
+ .toString();
+ }
+ if (size > 0) {
+ query.setSize(size);
+ } else {
+ return ResponseWrapper.paramErrorResponseFactory("size must be no smaller than 0, got " + size)
+ .toString();
+ }
+ }
+
+ ResponseWrapper response = this.getService().findAll(query);
+ return response.toString();
+ }
+
+
+ /**
+ * Query all related mitre objects of one by mitre id.
+ * The URL is {@code domain-name/query/{SOME_ID}/related}
+ * Can be accessed by both {@code GET} and {@code POST} method.
+ * the request parameter is {@code id}
+ *
+ * @param id the mitre_id of the object to be queried.x
+ * @return the mitre object in JSON format.
+ */
+ @RequestMapping(value = "{id}/related", method={RequestMethod.GET, RequestMethod.POST})
+ public String queryRelatedByStartNodeMitreId(@PathVariable String id) {
+
+ if (id == null) {
+ return ResponseWrapper.paramErrorResponseFactory("required: \"id\", found: none").toString();
+ }
+
+ QueryWrapper query = new QueryWrapper();
+ query.setMitreId(id);
+
+ ResponseWrapper response = this.getService().findRelatedWithoutRelationshipName(query);
+ return response.toString();
+ }
+
+
+ /**
+ * Query the specified relationship name between two given nodes.
+ * The URL is {@code domain-name/query/related}
+ * Can be accessed by both {@code GET} and {@code POST} method.
+ * the request parameter is {@code start_id} and {@code end_id}
+ *
+ * @param startNodeMitreId the mitre id of the start node.
+ * @param endNodeMitreId the mitre id of the end node.
+ * @return the relationship name
+ */
+ @RequestMapping(value = "/related", method={RequestMethod.GET, RequestMethod.POST})
+ public String queryRelationshipByStartAndEndNodeMitreId(@RequestParam(value = "start_id") String startNodeMitreId,
+ @RequestParam(value = "end_id") String endNodeMitreId) {
+
+ if (startNodeMitreId == null || endNodeMitreId == null) {
+ return ResponseWrapper.paramErrorResponseFactory("both \"start_id\" and \"end_id\" parameter required")
+ .toString();
+ }
+
+ QueryWrapper query = QueryWrapper.relationshipQueryFactory(startNodeMitreId, endNodeMitreId, null);
+ query.setType(GraphNode.getTypeFromMitreId(startNodeMitreId));
+
+ ResponseWrapper response = this.getService().findRelationship(query);
+ return response.toString();
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/UpdateController.java b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/UpdateController.java
new file mode 100644
index 0000000..b168e2a
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/UpdateController.java
@@ -0,0 +1,55 @@
+package uestc.zhanghanwen.ATTCK.RestWebControllers;
+
+import uestc.zhanghanwen.ATTCK.GraphCRUDServices.UpdateServices.UpdateServiceBundle;
+import uestc.zhanghanwen.ATTCK.Wrappers.ResponseWrapper;
+import uestc.zhanghanwen.ATTCK.Wrappers.QueryWrapper;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSON;
+import org.jetbrains.annotations.Contract;
+import lombok.Data;
+
+/**
+ * The RESTful controller class for all creating queries.
+ * The root URL path for this controller is {@code domain-name/create/}.
+ * The services are {@link UpdateController#updateNode}.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Data
+@RestController
+@RequestMapping(value = "/update")
+public class UpdateController {
+
+ UpdateServiceBundle service;
+
+ @Contract(pure = true)
+ public UpdateController(UpdateServiceBundle service) {
+ this.setService(service);
+ }
+
+ /**
+ * Update an existing node in the database.
+ *
+ * @param value the object id to delete
+ * @return true or false
+ */
+ @RequestMapping(value = "", method = {RequestMethod.GET, RequestMethod.POST})
+ public String updateNode(@RequestParam(value = "value") String value) {
+
+ JSONObject node = JSON.parseObject(value);
+ JSONArray nodes = new JSONArray();
+ nodes.add(0, node);
+
+ QueryWrapper request = new QueryWrapper();
+ request.setNodes(nodes);
+
+ ResponseWrapper response = this.getService().mergeNode(request);
+ return response.toString();
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/package-info.java
new file mode 100644
index 0000000..fa478f9
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/RestWebControllers/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * RESTful web controllers for CURD.
+ */
+package uestc.zhanghanwen.ATTCK.RestWebControllers;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/QueryWrapper.java b/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/QueryWrapper.java
new file mode 100644
index 0000000..ef34b54
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/QueryWrapper.java
@@ -0,0 +1,99 @@
+package uestc.zhanghanwen.ATTCK.Wrappers;
+
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONArray;
+import lombok.NoArgsConstructor;
+import lombok.Data;
+
+/**
+ * The encapsulation of different types of queries of all REST requests of CURD requests.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Data
+@NoArgsConstructor
+public class QueryWrapper {
+
+ /**
+ * The mitre id of the object to be queried.
+ */
+ private String mitreId;
+
+ /**
+ * The name of the object to be queried.
+ */
+ private String name;
+
+ /**
+ * The type to be queried.
+ */
+ private String type;
+
+ /**
+ * Is all results are got, else paged by {@link QueryWrapper#page} and {@link QueryWrapper#size}.
+ */
+ private boolean isGetAll;
+
+ /**
+ * If {@link QueryWrapper#isGetAll} is {@code false}, set the page.
+ */
+ private int page;
+
+ /**
+ * If {@link QueryWrapper#isGetAll} is {@code false}, set the size of the page.
+ */
+ private int size;
+
+ /**
+ * In the request of a relationship, two objects of serialized {@link GraphNode} can be put in.
+ */
+ private JSONArray nodes;
+
+ /**
+ * What relationship to be queried.
+ */
+ private String relationship;
+
+ /**
+ * Factory mode for generating {@link QueryWrapper} of querying relationship.
+ *
+ * @param startNodeMitreId The start node mitre id.
+ * @param endNodeMitreId The end node mitre id.
+ * @param relationship can be {@code null} if the above two are given.
+ * @return Generated {@link QueryWrapper}
+ */
+ public static QueryWrapper relationshipQueryFactory(String startNodeMitreId,
+ String endNodeMitreId,
+ String relationship) {
+
+ QueryWrapper query = new QueryWrapper();
+
+ JSONObject startNode = new JSONObject();
+ startNode.put("mitre_id", startNodeMitreId);
+ JSONObject endNode = new JSONObject();
+ endNode.put("mitre_id", endNodeMitreId);
+
+ query.setType(GraphNode.getTypeFromMitreId(startNodeMitreId));
+
+ JSONArray nodes = new JSONArray();
+ nodes.add(0, startNode);
+ nodes.add(1, endNode);
+
+ query.setNodes(nodes);
+ query.setRelationship(relationship);
+ return query;
+ }
+
+ /**
+ * Setter method for node.
+ * It also sets the type automatically by calling {@link GraphNode#getTypeFromMitreId}
+ *
+ * @param mitreId the id to be set.
+ */
+ public void setMitreId(String mitreId) {
+ this.mitreId = mitreId;
+ this.type = GraphNode.getTypeFromMitreId(mitreId);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/ResponseWrapper.java b/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/ResponseWrapper.java
new file mode 100644
index 0000000..b5ac9bd
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/ResponseWrapper.java
@@ -0,0 +1,245 @@
+package uestc.zhanghanwen.ATTCK.Wrappers;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSON;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import lombok.Data;
+
+/**
+ * The HTTP response should be sent to the client.
+ * The object can be serialized into {@code JSON string} via {@link ResponseWrapper#toString}
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Data
+public class ResponseWrapper {
+
+ /**
+ * OK response. value = {@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final int OK = 0;
+
+ /**
+ * Error request response. value = {@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final int REQUEST_ERROR = 1;
+
+ /**
+ * Server internal error response. value = {@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final int INTERNAL_ERROR = 2;
+
+ /**
+ * Code for no records. value={@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final int NO_RECORD = 3;
+
+ /**
+ * The record already exists if the query is to create. value = {@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final int ALREADY_EXIST = 4;
+
+ /**
+ * The message of {@link ResponseWrapper#OK}, value = {@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final String OK_MSG = "OK";
+
+ /**
+ * The message of {@link ResponseWrapper#REQUEST_ERROR}, value = {@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final String REQUEST_ERROR_MSG = "The parameters are contradicted from required.";
+
+ /**
+ * The message of {@link ResponseWrapper#INTERNAL_ERROR}, value = {@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final String INTERNAL_ERROR_MSG = "Server internal error.";
+
+ /**
+ * The message of {@link ResponseWrapper#NO_RECORD}, value = {@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final String NO_RECORD_MSG = "No record found in graph database.";
+
+ /**
+ * The message of {@link ResponseWrapper#ALREADY_EXIST}, value = {@value}
+ */
+ @JSONField(serialize = false, deserialize = false)
+ public static final String ALREADY_EXIST_MSG = "Could not insert, " +
+ "because it already exists in graph database, try update instead.";
+
+ /**
+ * The status of the current response.
+ *
+ * @see ResponseWrapper#OK
+ * @see ResponseWrapper#REQUEST_ERROR
+ * @see ResponseWrapper#INTERNAL_ERROR
+ * @see ResponseWrapper#NO_RECORD
+ * @see ResponseWrapper#ALREADY_EXIST
+ */
+ @JSONField(name = "status", ordinal = 1)
+ private int status;
+
+ /**
+ * The specified results of the query.
+ */
+ @NotNull
+ @JSONField(name = "result", ordinal = 2)
+ private JSONArray result;
+
+ /**
+ * The message of the current response.
+ *
+ * @see ResponseWrapper#OK_MSG
+ * @see ResponseWrapper#REQUEST_ERROR_MSG
+ * @see ResponseWrapper#INTERNAL_ERROR_MSG
+ * @see ResponseWrapper#NO_RECORD_MSG
+ * @see ResponseWrapper#ALREADY_EXIST_MSG
+ */
+ @NotNull
+ @JSONField(name = "msg", ordinal = 3)
+ private String msg;
+
+ /**
+ * The message for detail provided by {@link ResultWrapper}
+ *
+ * @see ResultWrapper#getMsgSpec
+ */
+ @JSONField(name = "detail", ordinal = 4)
+ private String detail;
+
+ /**
+ * Default constructor.
+ */
+ @Contract(pure = true)
+ public ResponseWrapper() {
+ this.setResult(new JSONArray());
+ this.setStatus(ResponseWrapper.NO_RECORD);
+ }
+
+ /**
+ * Add all results from a {@link JSONArray} in a {@link ResultWrapper} into it's own {@link ResponseWrapper#result}
+ *
+ * @param result the {@link ResultWrapper} of a query.
+ */
+ public void addAll(ResultWrapper result) {
+
+ switch (result.getStatusCode()) {
+
+ case ResultWrapper.OK:
+
+ if (this.status == ResponseWrapper.OK || this.status == NO_RECORD) {
+ this.getResult().addAll(result.getResult());
+ this.setStatus(ResponseWrapper.OK, result.getMsgSpec());
+ }
+ break;
+
+ case ResultWrapper.NO_RECORD:
+
+ if (this.status == ResponseWrapper.NO_RECORD) {
+ this.setDetail(result.getMsgSpec());
+ }
+ break;
+
+ case ResultWrapper.FAILED:
+
+ this.setStatus(ResponseWrapper.INTERNAL_ERROR, result.getMsgSpec());
+ break;
+
+ case ResultWrapper.ALREADY_EXIST:
+
+ if (this.status == ResponseWrapper.NO_RECORD) {
+ this.setStatus(ResponseWrapper.ALREADY_EXIST, result.getMsgSpec());
+ }
+ break;
+
+ case ResultWrapper.REQUEST_ERROR:
+
+ this.setStatus(ResponseWrapper.REQUEST_ERROR, result.getMsgSpec());
+ break;
+ }
+
+ }
+
+ /**
+ * Factory mode for generating request parameter error response.
+ *
+ * @param detail detail of the error.
+ * @return error response.
+ */
+ public static ResponseWrapper paramErrorResponseFactory(String detail) {
+ ResponseWrapper paramErrorResponse = new ResponseWrapper();
+ paramErrorResponse.setStatus(ResponseWrapper.REQUEST_ERROR, detail);
+ return paramErrorResponse;
+ }
+
+ /**
+ * Setter for {@link ResponseWrapper#status}.
+ * Also sets the corresponding {@link ResponseWrapper#msg}
+ *
+ * @param status the status to be set, note that it won't check for correctness.
+ * @see ResponseWrapper#OK
+ * @see ResponseWrapper#REQUEST_ERROR
+ * @see ResponseWrapper#INTERNAL_ERROR
+ * @see ResponseWrapper#NO_RECORD
+ * @see ResponseWrapper#ALREADY_EXIST
+ */
+ public void setStatus(int status) {
+
+ this.status = status;
+
+ if (status == ResponseWrapper.OK) {
+ this.setMsg(ResponseWrapper.OK_MSG);
+
+ } else if (status == ResponseWrapper.NO_RECORD) {
+ this.setMsg(ResponseWrapper.NO_RECORD_MSG);
+
+ } else if (status == ResponseWrapper.REQUEST_ERROR) {
+ this.setMsg(ResponseWrapper.REQUEST_ERROR_MSG);
+
+ } else if (status == ResponseWrapper.ALREADY_EXIST) {
+ this.setMsg(ResponseWrapper.ALREADY_EXIST_MSG);
+
+ } else if (status == ResponseWrapper.INTERNAL_ERROR) {
+ this.setMsg(ResponseWrapper.INTERNAL_ERROR_MSG);
+ }
+ }
+
+ /**
+ * Setter for {@link ResponseWrapper#status}.
+ * Also sets the corresponding {@link ResponseWrapper#msg} and {@link ResponseWrapper#detail}
+ *
+ * @param status the status to be set, note that it won't check for correctness.
+ * @param detail the detail to be set.
+ * @see ResponseWrapper#OK
+ * @see ResponseWrapper#REQUEST_ERROR
+ * @see ResponseWrapper#INTERNAL_ERROR
+ * @see ResponseWrapper#NO_RECORD
+ * @see ResponseWrapper#ALREADY_EXIST
+ */
+ public void setStatus(int status, String detail) {
+ this.setStatus(status);
+ this.setDetail(detail);
+ }
+
+
+ /**
+ * Serialize the object into {@link String} in the format of {@code JSON}
+ *
+ * @return {@code JSON string}
+ */
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/ResultWrapper.java b/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/ResultWrapper.java
new file mode 100644
index 0000000..a25e4d1
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/ResultWrapper.java
@@ -0,0 +1,135 @@
+package uestc.zhanghanwen.ATTCK.Wrappers;
+
+import uestc.zhanghanwen.ATTCK.POJOs.GraphNode;
+import com.alibaba.fastjson.JSONArray;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import java.util.Objects;
+import java.util.List;
+import lombok.Data;
+
+/**
+ * The encapsulation of query results to the database.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@Data
+public class ResultWrapper {
+
+ /**
+ * Successfully performed a query. value = {@value}
+ */
+ public static final int OK = 0;
+
+ /**
+ * No record found in the database. value = {@value}
+ */
+ public static final int NO_RECORD = 1;
+
+ /**
+ * Failed to query. value = {@value}
+ */
+ public static final int FAILED = 2;
+
+ /**
+ * Already exists if the query is to create. value = {@value}
+ */
+ public static final int ALREADY_EXIST = 3;
+
+ /**
+ * Error request response. value = {@value}
+ */
+ public static final int REQUEST_ERROR = 4;
+
+ /**
+ * The results of the query.
+ */
+ @NotNull
+ private JSONArray result;
+
+ /**
+ * The status of the current query.
+ *
+ * @see ResultWrapper#OK
+ * @see ResultWrapper#NO_RECORD
+ * @see ResultWrapper#FAILED
+ * @see ResultWrapper#ALREADY_EXIST
+ * @see ResultWrapper#REQUEST_ERROR
+ */
+ private int statusCode;
+
+ /**
+ * The specific message of error, null if OK.
+ */
+ private String msgSpec;
+
+ /**
+ * Constructor for initializing {@link ResultWrapper#statusCode}
+ * @param statusCode status code.
+ */
+ @Contract(pure = true)
+ public ResultWrapper(int statusCode) {
+ this.setStatusCode(statusCode);
+ }
+
+ /**
+ * Default constructor.
+ */
+ @Contract(pure = true)
+ public ResultWrapper() {
+ this.setStatusCode(ResultWrapper.NO_RECORD);
+ }
+
+ public String getMsgSpec() {
+ return Objects.requireNonNullElse(msgSpec, "");
+ }
+
+ /**
+ * Get the results from a {@link List} given by the {@link uestc.zhanghanwen.ATTCK.Repositories.NodeRepository}
+ * @param nodeList the results
+ * @param instance of {@link GraphNode}
+ * @return {@link ResultWrapper} of the results.
+ */
+ public static ResultWrapper resultFromList(@NotNull List nodeList) {
+ JSONArray array = new JSONArray();
+ array.addAll(nodeList);
+ ResultWrapper result = new ResultWrapper();
+ result.setResult(array);
+ if (nodeList.size() > 0) {
+ result.setStatusCode(ResultWrapper.OK);
+ } else {
+ result.setStatusCode(ResultWrapper.NO_RECORD);
+ }
+ return result;
+ }
+
+ /**
+ * Factory mode for query failure caused by internal error.
+ *
+ * @param e {@link Exception}
+ * @return error result
+ */
+ public static ResultWrapper errorResult(Exception e) {
+ ResultWrapper result = new ResultWrapper(ResultWrapper.FAILED);
+ result.setMsgSpec(e.getClass() + ": " + e.getMessage());
+ return result;
+ }
+
+ /**
+ * Factory mode for query failure caused by wrong type provided by user.
+ * @param type wrong type
+ * @return error result
+ */
+ public static ResultWrapper wrongTypeResult(String type) {
+
+ ResultWrapper result = new ResultWrapper(ResultWrapper.NO_RECORD);
+
+ if (type == null || type.equals("")) {
+ result.setMsgSpec("Type not provided, or cannot infer type from mitre id.");
+ } else {
+ result.setMsgSpec("Type '" + type + "' of node does not exist.");
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/package-info.java
new file mode 100644
index 0000000..b4180a6
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/Wrappers/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * Utility classes for encapsulation queries, results and responses.
+ *
+ * @see uestc.zhanghanwen.ATTCK.Wrappers.ResultWrapper results
+ * @see uestc.zhanghanwen.ATTCK.Wrappers.ResponseWrapper responses
+ * @see uestc.zhanghanwen.ATTCK.Wrappers.QueryWrapper queries
+ */
+package uestc.zhanghanwen.ATTCK.Wrappers;
\ No newline at end of file
diff --git a/src/main/java/uestc/zhanghanwen/ATTCK/package-info.java b/src/main/java/uestc/zhanghanwen/ATTCK/package-info.java
new file mode 100644
index 0000000..7c1af98
--- /dev/null
+++ b/src/main/java/uestc/zhanghanwen/ATTCK/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The ATT&CK backend project of neo4j database, using SpringBoot.
+ */
+package uestc.zhanghanwen.ATTCK;
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..d1c95b7
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.data.neo4j.uri=bolt://localhost:7687/
+spring.data.neo4j.username=neo4j
+spring.data.neo4j.password=attck
\ No newline at end of file
diff --git a/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/CreateControllerTest.java b/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/CreateControllerTest.java
new file mode 100644
index 0000000..f21cb84
--- /dev/null
+++ b/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/CreateControllerTest.java
@@ -0,0 +1,100 @@
+package uestc.zhanghanwen.ATTCK.RestWebControllers;
+
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.hamcrest.Matchers.containsString;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+import com.alibaba.fastjson.JSONObject;
+import org.junit.jupiter.api.Test;
+
+@SpringBootTest
+@AutoConfigureMockMvc
+class CreateControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ void createNode() throws Exception {
+
+ JSONObject toCreate = new JSONObject();
+
+ toCreate.put("name", "test1");
+ toCreate.put("mitre_id", "A");
+ toCreate.put("type", "matrix");
+
+ this.mockMvc.perform(get("/create/node").param("value", toCreate.toJSONString()))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+
+ toCreate = new JSONObject();
+
+ toCreate.put("name", "test2");
+ toCreate.put("mitre_id", "B");
+ toCreate.put("type", "matrix");
+
+ this.mockMvc.perform(get("/create/node").param("value", toCreate.toJSONString()))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void createNodeDuplicate() throws Exception {
+ JSONObject toCreate = new JSONObject();
+
+ toCreate.put("name", "test1");
+ toCreate.put("mitre_id", "A");
+ toCreate.put("type", "matrix");
+
+ this.mockMvc.perform(get("/create/node").param("value", toCreate.toJSONString()))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":4")));
+ }
+
+ @Test
+ void doNothing() throws Exception {
+ this.mockMvc.perform(get("/create"))
+ .andDo(print())
+ .andExpect(status().is4xxClientError());
+ }
+
+ @Test
+ void createRelationship() throws Exception {
+ this.mockMvc.perform(get("/create/relationship?start_id=A&end_id=B&relationship=in"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void createRelationshipDuplicate() throws Exception {
+ this.mockMvc.perform(get("/create/relationship?start_id=A&end_id=B&relationship=in"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":4")));
+ }
+
+ @Test
+ void createWrongRelationship() throws Exception {
+ this.mockMvc.perform(get("/create/relationship?start_id=A&end_id=B&relationship=out"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":1")));
+ }
+
+ @Test
+ void createWrongRelationshipNotExist() throws Exception {
+ this.mockMvc.perform(get("/create/relationship?start_id=C&end_id=B&relationship=in"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":3")));
+ }
+}
diff --git a/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/DeleteControllerTest.java b/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/DeleteControllerTest.java
new file mode 100644
index 0000000..64dec44
--- /dev/null
+++ b/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/DeleteControllerTest.java
@@ -0,0 +1,38 @@
+package uestc.zhanghanwen.ATTCK.RestWebControllers;
+
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+import static org.hamcrest.Matchers.containsString;
+import org.junit.jupiter.api.Test;
+
+@SpringBootTest
+@AutoConfigureMockMvc
+class DeleteControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ void deleteNode() throws Exception {
+
+ this.mockMvc.perform(get("/delete/node?id=A"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void deleteRelationships() throws Exception {
+
+ this.mockMvc.perform(get("/delete/relationship?start_id=A&end_id=B"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/RetrieveControllerTest.java b/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/RetrieveControllerTest.java
new file mode 100644
index 0000000..e9e33da
--- /dev/null
+++ b/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/RetrieveControllerTest.java
@@ -0,0 +1,143 @@
+package uestc.zhanghanwen.ATTCK.RestWebControllers;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+import static org.hamcrest.Matchers.containsString;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test Class for {@link RetrieveController}.
+ *
+ * @author zhanghanwen
+ * @version 1.0
+ */
+@SpringBootTest
+@AutoConfigureMockMvc
+class RetrieveControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ void test404() throws Exception {
+ this.mockMvc.perform(get("/queries"))
+ .andDo(print())
+ .andExpect(status().is4xxClientError());
+ }
+
+ @Test
+ void queryObject() throws Exception {
+ this.mockMvc.perform(get("/query?name=pre"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void queryObjectWithBlank() throws Exception {
+ this.mockMvc.perform(post("/query").param("name", "Initial Access"))
+ .andDo(print())
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ void queryObjectNotFound() throws Exception {
+ this.mockMvc.perform(get("/query?name=pr"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":3")));
+ }
+
+ @Test
+ void queryByMitreIdParameterRedirect() throws Exception {
+ this.mockMvc.perform(get("/query?id=MT0001"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void queryObjectByMitreId() throws Exception {
+ this.mockMvc.perform(get("/query/TA0001"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void queryObjectByMitreIdTypeNOTfound() throws Exception {
+ this.mockMvc.perform(get("/query/A0001"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":3")));
+ }
+
+ @Test
+ void queryType() throws Exception {
+ this.mockMvc.perform(get("/query/type/technique?page=5"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void queryTypeGetAll() throws Exception {
+ this.mockMvc.perform(get("/query/type/matrix?get_all=true"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void queryTypeNotFound() throws Exception {
+ this.mockMvc.perform(get("/query/type/g"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":3")));
+ }
+
+ @Test
+ void queryRelatedByMitreId() throws Exception {
+ this.mockMvc.perform(get("/query/MT0001/related"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void queryRelatedByMitreIdNotFound() throws Exception {
+ this.mockMvc.perform(get("/query/MT000/related"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":3")));
+ }
+
+ @Test
+ void queryRelationshipNotFound() throws Exception {
+ this.mockMvc.perform(get("/query/related?start_id=MT0001&end_id=TA0001"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":3")));
+ }
+
+ @Test
+ void queryRelationship() throws Exception {
+ this.mockMvc.perform(get("/query/related?start_id=MT0002&end_id=TA0001"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void queryRelationshipNotExist() throws Exception {
+ this.mockMvc.perform(get("/query/related?start_id=MT000&end_id=TA0001"))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":3")));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/UpdateControllerTest.java b/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/UpdateControllerTest.java
new file mode 100644
index 0000000..078a122
--- /dev/null
+++ b/src/test/java/uestc/zhanghanwen/ATTCK/RestWebControllers/UpdateControllerTest.java
@@ -0,0 +1,62 @@
+package uestc.zhanghanwen.ATTCK.RestWebControllers;
+
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+import static org.hamcrest.Matchers.containsString;
+import com.alibaba.fastjson.JSONObject;
+import org.junit.jupiter.api.Test;
+
+@SpringBootTest
+@AutoConfigureMockMvc
+class UpdateControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ void updateNode() throws Exception {
+
+ JSONObject toCreate = new JSONObject();
+
+ toCreate.put("name", "test0");
+ toCreate.put("mitre_id", "A");
+ toCreate.put("type", "matrix");
+
+ this.mockMvc.perform(get("/update").param("value", toCreate.toJSONString()))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+
+ toCreate = new JSONObject();
+
+ toCreate.put("name", "test1");
+ toCreate.put("mitre_id", "B");
+ toCreate.put("type", "matrix");
+
+ this.mockMvc.perform(get("/update").param("value", toCreate.toJSONString()))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":0")));
+ }
+
+ @Test
+ void updateNodeDoNotExist() throws Exception {
+
+ JSONObject toCreate = new JSONObject();
+
+ toCreate.put("name", "test0");
+ toCreate.put("mitre_id", "C");
+ toCreate.put("type", "matrix");
+
+ this.mockMvc.perform(get("/update").param("value", toCreate.toJSONString()))
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("\"status\":3")));
+ }
+}
\ No newline at end of file