diff --git a/CHANGELOG.md b/CHANGELOG.md index ef831e36d..559c85d73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,10 @@ **Implemented enhancements:** -- Update weasis-dicom-tools to 5.24.2 \(native lib to 4.5.3\) [\#177](https://github.com/OsiriX-Foundation/karnak/issues/177) -- DeIdentification front: refactoring + behaviour activate/deactivate deidentification [\#174](https://github.com/OsiriX-Foundation/karnak/issues/174) +- Update weasis-dicom-tools to 5.24.2 \(native lib to + 4.5.3\) [\#177](https://github.com/OsiriX-Foundation/karnak/issues/177) +- DeIdentification front: refactoring + behaviour activate/deactivate + deidentification [\#174](https://github.com/OsiriX-Foundation/karnak/issues/174) - Notification Front: default values [\#172](https://github.com/OsiriX-Foundation/karnak/issues/172) - Karnak email address [\#159](https://github.com/OsiriX-Foundation/karnak/issues/159) - Change configuration when sending [\#31](https://github.com/OsiriX-Foundation/karnak/issues/31) @@ -19,18 +21,25 @@ **Implemented enhancements:** - Adjust clickable zone checkbox [\#169](https://github.com/OsiriX-Foundation/karnak/issues/169) -- Add profile version in projects views [\#167](https://github.com/OsiriX-Foundation/karnak/issues/167) -- Springboot/junit/liquibase versions upgrade [\#165](https://github.com/OsiriX-Foundation/karnak/issues/165) -- Enable/disable destination buttons \(save/delete\) when transfer is in progress [\#163](https://github.com/OsiriX-Foundation/karnak/issues/163) -- Destinations: loading spinner transfer activity [\#161](https://github.com/OsiriX-Foundation/karnak/issues/161) -- Image transcoding with a specific transfer syntax [\#139](https://github.com/OsiriX-Foundation/karnak/issues/139) +- Add profile version in projects + views [\#167](https://github.com/OsiriX-Foundation/karnak/issues/167) +- Springboot/junit/liquibase versions + upgrade [\#165](https://github.com/OsiriX-Foundation/karnak/issues/165) +- Enable/disable destination buttons \(save/delete\) when transfer is in + progress [\#163](https://github.com/OsiriX-Foundation/karnak/issues/163) +- Destinations: loading spinner transfer + activity [\#161](https://github.com/OsiriX-Foundation/karnak/issues/161) +- Image transcoding with a specific transfer + syntax [\#139](https://github.com/OsiriX-Foundation/karnak/issues/139) - Inject an external id provider [\#88](https://github.com/OsiriX-Foundation/karnak/issues/88) -- Check that the expression does not corrupt the DICOM [\#74](https://github.com/OsiriX-Foundation/karnak/issues/74) +- Check that the expression does not corrupt the + DICOM [\#74](https://github.com/OsiriX-Foundation/karnak/issues/74) - Improve the notification module UI [\#42](https://github.com/OsiriX-Foundation/karnak/issues/42) **Fixed bugs:** -- Switching in the KHEOPS album cannot be applied with the KEEP action on the study UID and / or the serial UID [\#156](https://github.com/OsiriX-Foundation/karnak/issues/156) +- Switching in the KHEOPS album cannot be applied with the KEEP action on the study UID and / or the + serial UID [\#156](https://github.com/OsiriX-Foundation/karnak/issues/156) ## [v0.9.7](https://github.com/OsiriX-Foundation/karnak/tree/v0.9.7) (2021-06-11) @@ -38,17 +47,22 @@ **Implemented enhancements:** -- Remove use pseudonym as patient name button and use pseudonym for patient name [\#154](https://github.com/OsiriX-Foundation/karnak/issues/154) -- Check Issuer of Patient ID in destination [\#148](https://github.com/OsiriX-Foundation/karnak/issues/148) -- Load an external logback configuration at startup [\#128](https://github.com/OsiriX-Foundation/karnak/issues/128) +- Remove use pseudonym as patient name button and use pseudonym for patient + name [\#154](https://github.com/OsiriX-Foundation/karnak/issues/154) +- Check Issuer of Patient ID in + destination [\#148](https://github.com/OsiriX-Foundation/karnak/issues/148) +- Load an external logback configuration at + startup [\#128](https://github.com/OsiriX-Foundation/karnak/issues/128) - Set the logging level at startup [\#119](https://github.com/OsiriX-Foundation/karnak/issues/119) - Pattern for the Clinical log warning [\#85](https://github.com/OsiriX-Foundation/karnak/issues/85) - Defacing CT [\#17](https://github.com/OsiriX-Foundation/karnak/issues/17) **Fixed bugs:** -- The order of profile elements on the ui and when downloading a profile is not correct. [\#146](https://github.com/OsiriX-Foundation/karnak/issues/146) -- Do not de-identify when multiple actions and with retired SOP Class UID [\#138](https://github.com/OsiriX-Foundation/karnak/issues/138) +- The order of profile elements on the ui and when downloading a profile is not + correct. [\#146](https://github.com/OsiriX-Foundation/karnak/issues/146) +- Do not de-identify when multiple actions and with retired SOP Class + UID [\#138](https://github.com/OsiriX-Foundation/karnak/issues/138) - Fix endianness of added sequences [\#137](https://github.com/OsiriX-Foundation/karnak/issues/137) ## [v0.9.6](https://github.com/OsiriX-Foundation/karnak/tree/v0.9.6) (2021-05-07) @@ -57,16 +71,21 @@ **Implemented enhancements:** -- Modal windows for the element of dicom worklist [\#135](https://github.com/OsiriX-Foundation/karnak/issues/135) -- Bump vaadin.version from 17.0.10 to 19.0.5 [\#133](https://github.com/OsiriX-Foundation/karnak/issues/133) +- Modal windows for the element of dicom + worklist [\#135](https://github.com/OsiriX-Foundation/karnak/issues/135) +- Bump vaadin.version from 17.0.10 to + 19.0.5 [\#133](https://github.com/OsiriX-Foundation/karnak/issues/133) - remove the checkbox Authorized SOPs [\#97](https://github.com/OsiriX-Foundation/karnak/issues/97) -- Raise an exception from the execute function of an action. [\#73](https://github.com/OsiriX-Foundation/karnak/issues/73) +- Raise an exception from the execute function of an + action. [\#73](https://github.com/OsiriX-Foundation/karnak/issues/73) - \[Clean Pixel\] Recompression issue [\#39](https://github.com/OsiriX-Foundation/karnak/issues/39) **Fixed bugs:** -- Decompress all the images with DICOM output [\#136](https://github.com/OsiriX-Foundation/karnak/issues/136) -- STOW-RS exceptions when sending images from multiple sources concurrently [\#124](https://github.com/OsiriX-Foundation/karnak/issues/124) +- Decompress all the images with DICOM + output [\#136](https://github.com/OsiriX-Foundation/karnak/issues/136) +- STOW-RS exceptions when sending images from multiple sources + concurrently [\#124](https://github.com/OsiriX-Foundation/karnak/issues/124) ## [v0.9.5](https://github.com/OsiriX-Foundation/karnak/tree/v0.9.5) (2021-04-16) @@ -78,7 +97,8 @@ **Fixed bugs:** -- Exception loading sessions from persistent storage [\#127](https://github.com/OsiriX-Foundation/karnak/issues/127) +- Exception loading sessions from persistent + storage [\#127](https://github.com/OsiriX-Foundation/karnak/issues/127) ## [v0.9.4](https://github.com/OsiriX-Foundation/karnak/tree/v0.9.4) (2021-03-17) @@ -86,16 +106,23 @@ **Implemented enhancements:** -- Reorganization in the types of pseudonyms and improvement the management of pseudonyms [\#118](https://github.com/OsiriX-Foundation/karnak/issues/118) -- Display a unique message when we add multiple same external pseudonym via the csv file [\#108](https://github.com/OsiriX-Foundation/karnak/issues/108) -- Linking external pseudonym to a project [\#107](https://github.com/OsiriX-Foundation/karnak/issues/107) -- Pagination to visualize the External Pseudonym view [\#106](https://github.com/OsiriX-Foundation/karnak/issues/106) +- Reorganization in the types of pseudonyms and improvement the management of + pseudonyms [\#118](https://github.com/OsiriX-Foundation/karnak/issues/118) +- Display a unique message when we add multiple same external pseudonym via the csv + file [\#108](https://github.com/OsiriX-Foundation/karnak/issues/108) +- Linking external pseudonym to a + project [\#107](https://github.com/OsiriX-Foundation/karnak/issues/107) +- Pagination to visualize the External Pseudonym + view [\#106](https://github.com/OsiriX-Foundation/karnak/issues/106) **Fixed bugs:** -- Manage exception if status code is not SUCCESSFUL for a dicom stow [\#117](https://github.com/OsiriX-Foundation/karnak/issues/117) -- Manage exception on parsing datetime [\#116](https://github.com/OsiriX-Foundation/karnak/issues/116) -- Incorrect trailing \(FFFE,E00D\) Item Delimitation Item in outgoing C-STORE RQs. [\#109](https://github.com/OsiriX-Foundation/karnak/issues/109) +- Manage exception if status code is not SUCCESSFUL for a dicom + stow [\#117](https://github.com/OsiriX-Foundation/karnak/issues/117) +- Manage exception on parsing + datetime [\#116](https://github.com/OsiriX-Foundation/karnak/issues/116) +- Incorrect trailing \(FFFE,E00D\) Item Delimitation Item in outgoing C-STORE + RQs. [\#109](https://github.com/OsiriX-Foundation/karnak/issues/109) ## [v0.9.3.1](https://github.com/OsiriX-Foundation/karnak/tree/v0.9.3.1) (2021-02-05) @@ -103,7 +130,8 @@ **Fixed bugs:** -- Profile format is not correct when it exported [\#111](https://github.com/OsiriX-Foundation/karnak/issues/111) +- Profile format is not correct when it + exported [\#111](https://github.com/OsiriX-Foundation/karnak/issues/111) ## [v0.9.3](https://github.com/OsiriX-Foundation/karnak/tree/v0.9.3) (2021-02-01) @@ -111,33 +139,43 @@ **Implemented enhancements:** -- Pop up warning when regenerate Project secret [\#92](https://github.com/OsiriX-Foundation/karnak/issues/92) -- Simplify the pseudonym cache metadata [\#90](https://github.com/OsiriX-Foundation/karnak/issues/90) -- In the UI, split the pseudonym cache and mainzelliste [\#89](https://github.com/OsiriX-Foundation/karnak/issues/89) +- Pop up warning when regenerate Project + secret [\#92](https://github.com/OsiriX-Foundation/karnak/issues/92) +- Simplify the pseudonym cache + metadata [\#90](https://github.com/OsiriX-Foundation/karnak/issues/90) +- In the UI, split the pseudonym cache and + mainzelliste [\#89](https://github.com/OsiriX-Foundation/karnak/issues/89) - Pass the action logs to level TRACE [\#84](https://github.com/OsiriX-Foundation/karnak/issues/84) -- Remove all references to the secret KARNAK\_HMAC\_KEY [\#81](https://github.com/OsiriX-Foundation/karnak/issues/81) -- Add Instance Creation Date and Time attributes [\#79](https://github.com/OsiriX-Foundation/karnak/issues/79) +- Remove all references to the secret + KARNAK\_HMAC\_KEY [\#81](https://github.com/OsiriX-Foundation/karnak/issues/81) +- Add Instance Creation Date and Time + attributes [\#79](https://github.com/OsiriX-Foundation/karnak/issues/79) - Update help view [\#78](https://github.com/OsiriX-Foundation/karnak/issues/78) - Add rolling log for clinical log [\#77](https://github.com/OsiriX-Foundation/karnak/issues/77) - Remove a profile [\#76](https://github.com/OsiriX-Foundation/karnak/issues/76) - Improve the performance of the logs [\#67](https://github.com/OsiriX-Foundation/karnak/issues/67) - Show masks in the profiles page [\#61](https://github.com/OsiriX-Foundation/karnak/issues/61) - Export a profile [\#60](https://github.com/OsiriX-Foundation/karnak/issues/60) -- Reformat the code with google-java-format [\#40](https://github.com/OsiriX-Foundation/karnak/issues/40) +- Reformat the code with + google-java-format [\#40](https://github.com/OsiriX-Foundation/karnak/issues/40) - Upgrade of version [\#23](https://github.com/OsiriX-Foundation/karnak/issues/23) -- Use of the DICOM structure according to Information Object Definition \(IOD\) [\#11](https://github.com/OsiriX-Foundation/karnak/issues/11) +- Use of the DICOM structure according to Information Object Definition + \(IOD\) [\#11](https://github.com/OsiriX-Foundation/karnak/issues/11) **Fixed bugs:** -- Upload profile error on Chrome [\#93](https://github.com/OsiriX-Foundation/karnak/issues/93) +- Upload profile error on Chrome [\#93](https://github.com/OsiriX-Foundation/karnak/issues/93) - Missing level in log file [\#68](https://github.com/OsiriX-Foundation/karnak/issues/68) -- Hazelcast ClassNotFoundException in docker environment [\#66](https://github.com/OsiriX-Foundation/karnak/issues/66) +- Hazelcast ClassNotFoundException in docker + environment [\#66](https://github.com/OsiriX-Foundation/karnak/issues/66) **Closed issues:** -- Logs the following fields for each de-identified instance in clinical logs \(Serie UID, Instance UID, ...\) [\#83](https://github.com/OsiriX-Foundation/karnak/issues/83) +- Logs the following fields for each de-identified instance in clinical logs \(Serie UID, Instance + UID, ...\) [\#83](https://github.com/OsiriX-Foundation/karnak/issues/83) - Add mask view in profile view [\#71](https://github.com/OsiriX-Foundation/karnak/issues/71) -- Creation of a website for the karnak doc [\#70](https://github.com/OsiriX-Foundation/karnak/issues/70) +- Creation of a website for the karnak + doc [\#70](https://github.com/OsiriX-Foundation/karnak/issues/70) ## [0.9.2](https://github.com/OsiriX-Foundation/karnak/tree/0.9.2) (2020-11-04) @@ -145,14 +183,17 @@ **Implemented enhancements:** -- Reduce information in clinical log [\#56](https://github.com/OsiriX-Foundation/karnak/issues/56) -- Using caching for the Mainzelliste pseudonym [\#53](https://github.com/OsiriX-Foundation/karnak/issues/53) -- Improve the performance of pseudonym caching [\#52](https://github.com/OsiriX-Foundation/karnak/issues/52) +- Reduce information in clinical log [\#56](https://github.com/OsiriX-Foundation/karnak/issues/56) +- Using caching for the Mainzelliste + pseudonym [\#53](https://github.com/OsiriX-Foundation/karnak/issues/53) +- Improve the performance of pseudonym + caching [\#52](https://github.com/OsiriX-Foundation/karnak/issues/52) - Optimisation in actions [\#45](https://github.com/OsiriX-Foundation/karnak/issues/45) - Upgrade Spring and Vaadin [\#41](https://github.com/OsiriX-Foundation/karnak/issues/41) - Use DICOM endpoint as URL [\#36](https://github.com/OsiriX-Foundation/karnak/issues/36) - Warning No projects created [\#35](https://github.com/OsiriX-Foundation/karnak/issues/35) -- Option shift date, keep year, month or day [\#30](https://github.com/OsiriX-Foundation/karnak/issues/30) +- Option shift date, keep year, month or + day [\#30](https://github.com/OsiriX-Foundation/karnak/issues/30) - Expression in replace [\#28](https://github.com/OsiriX-Foundation/karnak/issues/28) - UI navigation [\#24](https://github.com/OsiriX-Foundation/karnak/issues/24) - Switching in different KHEOPS' album [\#16](https://github.com/OsiriX-Foundation/karnak/issues/16) @@ -162,18 +203,28 @@ **Fixed bugs:** -- Validator applied to null fields after adding a new project [\#59](https://github.com/OsiriX-Foundation/karnak/issues/59) -- The project grid doesn't update after updating a project [\#58](https://github.com/OsiriX-Foundation/karnak/issues/58) +- Validator applied to null fields after adding a new + project [\#59](https://github.com/OsiriX-Foundation/karnak/issues/59) +- The project grid doesn't update after updating a + project [\#58](https://github.com/OsiriX-Foundation/karnak/issues/58) - What happens with a null UID [\#57](https://github.com/OsiriX-Foundation/karnak/issues/57) - Define an "all" log file size [\#55](https://github.com/OsiriX-Foundation/karnak/issues/55) -- Sequences are not fully removed with Action X [\#51](https://github.com/OsiriX-Foundation/karnak/issues/51) -- Image with Clean pixel data is not sent to a DICOMWeb destination [\#50](https://github.com/OsiriX-Foundation/karnak/issues/50) -- DICOM connection between the forward node and the destination is closed randomly [\#49](https://github.com/OsiriX-Foundation/karnak/issues/49) -- Applying masks doesn't work when sending simultaneously several dataset [\#48](https://github.com/OsiriX-Foundation/karnak/issues/48) -- Notification for a DICOM destination doesn't work [\#47](https://github.com/OsiriX-Foundation/karnak/issues/47) -- Notification is not consistent when UIDs are changed by de-identification [\#46](https://github.com/OsiriX-Foundation/karnak/issues/46) -- NPE when setting a string value to Binary VR [\#44](https://github.com/OsiriX-Foundation/karnak/issues/44) -- Propagation of the action in sequence [\#29](https://github.com/OsiriX-Foundation/karnak/issues/29) +- Sequences are not fully removed with Action + X [\#51](https://github.com/OsiriX-Foundation/karnak/issues/51) +- Image with Clean pixel data is not sent to a DICOMWeb + destination [\#50](https://github.com/OsiriX-Foundation/karnak/issues/50) +- DICOM connection between the forward node and the destination is closed + randomly [\#49](https://github.com/OsiriX-Foundation/karnak/issues/49) +- Applying masks doesn't work when sending simultaneously several + dataset [\#48](https://github.com/OsiriX-Foundation/karnak/issues/48) +- Notification for a DICOM destination doesn't + work [\#47](https://github.com/OsiriX-Foundation/karnak/issues/47) +- Notification is not consistent when UIDs are changed by + de-identification [\#46](https://github.com/OsiriX-Foundation/karnak/issues/46) +- NPE when setting a string value to Binary + VR [\#44](https://github.com/OsiriX-Foundation/karnak/issues/44) +- Propagation of the action in + sequence [\#29](https://github.com/OsiriX-Foundation/karnak/issues/29) - Changing parameters during sending [\#26](https://github.com/OsiriX-Foundation/karnak/issues/26) ## [0.9.1](https://github.com/OsiriX-Foundation/karnak/tree/0.9.1) (2020-09-07) @@ -182,7 +233,8 @@ **Implemented enhancements:** -- Verification and error checking on the structure of the yaml file containing the profile [\#25](https://github.com/OsiriX-Foundation/karnak/issues/25) +- Verification and error checking on the structure of the yaml file containing the + profile [\#25](https://github.com/OsiriX-Foundation/karnak/issues/25) - Expression in option or profile [\#22](https://github.com/OsiriX-Foundation/karnak/issues/22) - Refactor constructor of ProfileItem [\#21](https://github.com/OsiriX-Foundation/karnak/issues/21) - Option with Date [\#19](https://github.com/OsiriX-Foundation/karnak/issues/19) @@ -201,6 +253,5 @@ - Vaadin Upgrade to v16 [\#6](https://github.com/OsiriX-Foundation/karnak/issues/6) - Select all filters [\#5](https://github.com/OsiriX-Foundation/karnak/issues/5) - - -\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* +\* *This Changelog was automatically generated +by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/Dockerfile b/Dockerfile index 7d3c5086b..639c245d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,8 @@ # docker build -t osirixfoundation/karnak:latest -f Dockerfile . # Based on build image containing maven, jdk and git -FROM maven:3.6-adoptopenjdk-15 as builder +#FROM maven:3.8-eclipse-temurin-17 as builder +FROM maven:3.6-openjdk-17 as builder WORKDIR /app # Build the Spring Boot application with layers @@ -16,8 +17,9 @@ RUN cp ../target/karnak*.jar application.jar RUN java -Djarmode=layertools -jar application.jar extract # Build the final deployment image -FROM adoptopenjdk:15-jre-hotspot +FROM eclipse-temurin:17-jdk-jammy WORKDIR app + COPY --from=builder /app/bin/dependencies/ ./ RUN true COPY --from=builder /app/bin/spring-boot-loader/ ./ diff --git a/Jenkinsfile b/Jenkinsfile index b649c44e6..393a978cc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,3 @@ @Library('hug-dsi@master') _ import ch.hcuge.dsi.jenkins.BuildImage; -newGenMavenPipeline(mavenImage: BuildImage.MVN_36_JDK15) \ No newline at end of file +newGenMavenPipeline(mavenImage: BuildImage.MVN_36_JDK17) diff --git a/README.md b/README.md index c164ed506..7884e93d0 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ output. For more information, see the online [Karnak user guide](https://osirix-foundation.github.io/karnak-documentation/) -:warning: **Security**: Karnak is using Logback and is not affected by CVE-2021-44228. [CVE-2021-42550 has been fixed](https://github.com/OsiriX-Foundation/karnak/issues/180) since v0.9.9 +:warning: **Security**: Karnak is using Logback and is not affected by +CVE-2021-44228. [CVE-2021-42550 has been fixed](https://github.com/OsiriX-Foundation/karnak/issues/180) +since v0.9.9 # Application Features @@ -53,7 +55,8 @@ see [karnak-docker](https://github.com/OsiriX-Foundation/karnak-docker). - Enable Spring and Spring Boot for the project - Create a Spring Boot launcher from main of StartApplication.java - Working Directory must be the mvc directory - - In VM Options, add `-Djava.library.path="/tmp/dicom-opencv"`. Note: the tmp folder must be adapted according to your system and `dicom-opencv` is mandatory as the last folder. + - In VM Options, add `-Djava.library.path="/tmp/dicom-opencv"`. Note: the tmp folder must be + adapted according to your system and `dicom-opencv` is mandatory as the last folder. - In Environment variables, add the following values. The following values work with our default configuration define with docker used for the development (see: "Configure locally Mainzelliste and Postgres database with docker-compose") : @@ -80,7 +83,7 @@ see [karnak-docker](https://github.com/OsiriX-Foundation/karnak-docker). - `OIDC_CLIENT_ID=undefined` - `OIDC_CLIENT_SECRET=undefined` - `OIDC_ISSUER_URI=undefined` - + ## Configure locally Mainzelliste and Postgres database with docker-compose Minimum docker-compose version: **1.22** @@ -120,8 +123,8 @@ See [all the environment variables](https://github.com/OsiriX-Foundation/karnak- This project is divided in two parts: -- backend: spring data (entities, repositories, converters, validators), enums, - spring configurations, spring security, cache, spring services, models... +- backend: spring data (entities, repositories, converters, validators), enums, + spring configurations, spring security, cache, spring services, models... - frontend : Vaadin components: logic services, graphic components, views # Logs Kibana @@ -129,23 +132,26 @@ This project is divided in two parts: In order to activate the logs in Kibana, activate the profile docker (from application-docker.yml) in the pom.xml : spring.profiles.active -The logs can be seen here: +The logs can be seen here: + - https://kibana-cert/s/spring/app/kibana#/discover - with the filter springAppName : karnak # Identity provider An OpenID Connect identity provider can be configured by using the environment variables: - - `IDP`: when this environment variable has the value 'oidc', the following environment - variables will configure the OpenID Connect identity provider. Any other value will load the in - memory user configuration. - - `OIDC_CLIENT_ID`: client id of the identity provider - - `OIDC_CLIENT_SECRET`: client secret of the identity provider - - `OIDC_ISSUER_URI`: issuer URI of the identity provider - -# Documentation for API/Endpoints + +- `IDP`: when this environment variable has the value 'oidc', the following environment + variables will configure the OpenID Connect identity provider. Any other value will load the in + memory user configuration. +- `OIDC_CLIENT_ID`: client id of the identity provider +- `OIDC_CLIENT_SECRET`: client secret of the identity provider +- `OIDC_ISSUER_URI`: issuer URI of the identity provider + +# Documentation for API/Endpoints In order to see the documentation for API/Endpoints: + - Local: http://localhost:8081/swagger-ui/index.html?url=/v3/api-docs - Dev: https://karnak-dev.hcuge.ch/swagger-ui/index.html?url=/v3/api-docs - Cert: https://karnak-cert.hcuge.ch/swagger-ui/index.html?url=/v3/api-docs diff --git a/doc/README.md b/doc/README.md index 43b185efc..618e64e6b 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,11 +1,17 @@ -KARNAK is a gateway for sending DICOM files to one or multiple Application Entity Title (AET).KARNAK offers the possibility to configure multiple destination for an AET. +KARNAK is a gateway for sending DICOM files to one or multiple Application Entity Title (AET).KARNAK +offers the possibility to configure multiple destination for an AET. These destinations can communicate with the DICOM or DICOM WEB protocol. -Besides different configurations of the destination like the DICOM endpoint or the credentials, it’s possible to assign a project to a destination. +Besides different configurations of the destination like the DICOM endpoint or the credentials, it’s +possible to assign a project to a destination. -A project defined the de-idenfication method and a secret that will be used for generate random values as UID or the shift date. +A project defined the de-idenfication method and a secret that will be used for generate random +values as UID or the shift date. -The reference profile of de-identification is given by the [DICOM standard](hehttp://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html). This profile offer an exhaustive list of DICOM tags to manage to allow the de-identification of the instance. +The reference profile of de-identification is given by +the [DICOM standard](hehttp://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html) +. This profile offer an exhaustive list of DICOM tags to manage to allow the de-identification of +the instance. To manage the tags defined, the Basic Prof. offer 5 actions to be carried out. @@ -15,15 +21,26 @@ To manage the tags defined, the Basic Prof. offer 5 actions to be carried out. * K – Keep * U – Replace with a new UID -The Basic Profile assigns one or more actions to a list of Tags. The multiple actions, show below, is propose to avoid the DICOM corruption. For example the [DICOM's type](http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_7.4.html) can evolve with the [Information Object Definiton (IOD)](http://dicom.nema.org/medical/dicom/current/output/chtml/part04/chapter_6.html) of the instance. This mean that an action like REMOVE can’t be applied on a Type 1 or Type 2 of the tag. +The Basic Profile assigns one or more actions to a list of Tags. The multiple actions, show below, +is propose to avoid the DICOM corruption. For example +the [DICOM's type](http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_7.4.html) can evolve +with +the [Information Object Definiton (IOD)](http://dicom.nema.org/medical/dicom/current/output/chtml/part04/chapter_6.html) +of the instance. This mean that an action like REMOVE can’t be applied on a Type 1 or Type 2 of the +tag. * Z/D – Z unless D is required to maintain IOD conformance (Type 2 versus Type 1) * X/Z – X unless Z is required to maintain IOD conformance (Type 3 versus Type 2) * X/D – X unless Z is required to maintain IOD conformance (Type 3 versus Type 1) -* X/Z/D – X unless Z or D is required to maintain IOD conformance (Type 3 versus Type 2 versus Type 1) -* X/Z/U* – X unless Z or replacement of contained instance UIDs (U) is required to maintain IOD conformance (Type 3 versus Type 2 versus Type 1 sequences containing UID references) +* X/Z/D – X unless Z or D is required to maintain IOD conformance (Type 3 versus Type 2 versus Type + 1) +* X/Z/U* – X unless Z or replacement of contained instance UIDs (U) is required to maintain IOD + conformance (Type 3 versus Type 2 versus Type 1 sequences containing UID references) -For the moment KARNAK does not know the IOD structure and therefore the types of tags that it must process, we decided to assign the strictest action to the Tag when a multiple action is offered to us (U/D > Z > X). Below is the action which is applied when multiple actions are proposed by the Basic Profile +For the moment KARNAK does not know the IOD structure and therefore the types of tags that it must +process, we decided to assign the strictest action to the Tag when a multiple action is offered to +us (U/D > Z > X). Below is the action which is applied when multiple actions are proposed by the +Basic Profile * Z/D, X/D, X/Z/D → apply action D * X/Z → apply action Z @@ -31,53 +48,82 @@ For the moment KARNAK does not know the IOD structure and therefore the types of ## Action D without dummy value -The action D must replace the Tag’s field with a dummy value. This field must be consistent with the [Value Representation](http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html) (VR) of the Tag. +The action D must replace the Tag’s field with a dummy value. This field must be consistent with +the [Value Representation](http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html) ( +VR) of the Tag. KARNAK will use a default value by VR in this case. * AE, CS, LO, LT, PN, SH, ST, UN, UT, UC, UR → “UNKNOWN” * DS, IS → “0” -* AS, DA, DT, TM → shiftRange(), the generation of a date will be explained below, **Shift Date, Generate a random date** -* UI → Action U, the generation of a new UID will be explained below, see **Action U, Generate a new UID**. +* AS, DA, DT, TM → shiftRange(), the generation of a date will be explained below, **Shift Date, + Generate a random date** +* UI → Action U, the generation of a new UID will be explained below, see **Action U, Generate a new + UID**. -The *shiftRange()* gives random value between a given max days and seconds. By default the max days defined is **365** and the max seconds is **86400**. +The *shiftRange()* gives random value between a given max days and seconds. By default the max days +defined is **365** and the max seconds is **86400**. -The following VRs *FL, FD, SL, SS, UL, US* are of type Binary. By default KARNAK will set to null the value of this VR. +The following VRs *FL, FD, SL, SS, UL, US* are of type Binary. By default KARNAK will set to null +the value of this VR. ## Action U, Generate a new UID -For each U action, KARNAK will hash the input value. A one-way function is created to ensure that it is not possible to revert to the original UID. This function will hash the input UID and generate a UID from the hashed input. +For each U action, KARNAK will hash the input value. A one-way function is created to ensure that it +is not possible to revert to the original UID. This function will hash the input UID and generate a +UID from the hashed input. ### Context -It’s possible for a DICOM study to be de-identified several times and in different ways. This means that if a study is de-identified with specific characteristics, it will not be the same as if it is de-identified with other characteristics. So for each way to de-identified, a new UID will be generated even if it is the same input study. +It’s possible for a DICOM study to be de-identified several times and in different ways. This means +that if a study is de-identified with specific characteristics, it will not be the same as if it is +de-identified with other characteristics. So for each way to de-identified, a new UID will be +generated even if it is the same input study. -To ensure UID generation by de-identification method, a project will be associate to the destination. In KARNAK, a project must be create to use the de-idenfication. A project defined a de-idenfication method and a secret generate randomly or import by the user. **The project's secret will be use as key for the HMAC.** +To ensure UID generation by de-identification method, a project will be associate to the +destination. In KARNAK, a project must be create to use the de-idenfication. A project defined a +de-idenfication method and a secret generate randomly or import by the user. **The project's secret +will be use as key for the HMAC.** #### Project secret **The secret is 16 bytes** defined randomly when the project is created. -An user can upload his own secret, but the uploaded secret must be 16 bytes. To allow easy uploading of secrets to the user, KARNAK offers to upload it in hexadecimal. +An user can upload his own secret, but the uploaded secret must be 16 bytes. To allow easy uploading +of secrets to the user, KARNAK offers to upload it in hexadecimal. ### Hash function -The algorithm used for hashing is the “Message Authentication Code” (MAC). KARNAK used the MAC, not as message authentication, but as a one-way function. A definition, coming from the [JAVA Mac class](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/javax/crypto/Mac.html) used, is proposed to you here below: +The algorithm used for hashing is the “Message Authentication Code” (MAC). KARNAK used the MAC, not +as message authentication, but as a one-way function. A definition, coming from +the [JAVA Mac class](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/javax/crypto/Mac.html) +used, is proposed to you here below: -« *A MAC provides a way to check the integrity of information transmitted over or stored in an unreliable medium, based on a secret key. Typically, message authentication codes are used between two parties that share a secret key in order to validate information transmitted between these parties.* +«*A MAC provides a way to check the integrity of information transmitted over or stored in an +unreliable medium, based on a secret key. Typically, message authentication codes are used between +two parties that share a secret key in order to validate information transmitted between these +parties.* -*A MAC mechanism that is based on cryptographic hash functions is referred to as HMAC. HMAC can be used with any cryptographic hash function, e.g., SHA256 or SHA384, in combination with a secret shared key. HMAC is specified in RFC 2104.* » +*A MAC mechanism that is based on cryptographic hash functions is referred to as HMAC. HMAC can be +used with any cryptographic hash function, e.g., SHA256 or SHA384, in combination with a secret +shared key. HMAC is specified in RFC 2104.*» For each use of the HMAC, it uses the **SHA256** hash function **with a project's secret given**. ### Generate UID -“*What DICOM calls a "UID" is referred to in the ISO OSI world as an Object Identifier (OID)*”[1] To generate the new DICOM UID, KARNAK will create an OID that begins with “2.25” (is an OID encoded UUID). “*The value after "2.25." is the straight decimal encoding of the UUID as an integer. It MUST be a direct decimal encoding of the single integer, all 128 bits.*”[2] +“*What DICOM calls a "UID" is referred to in the ISO OSI world as an Object Identifier(OID)*”[1] To +generate the new DICOM UID, KARNAK will create an OID that begins with “2.25” (is an OID encoded +UUID). “*The value after "2.25." is the straight decimal encoding of the UUID as an integer. It MUST +be a direct decimal encoding of the single integer, all 128 bits.*”[2] [1]: + [2]: https://wiki.ihe.net/index.php/Creating_Unique_IDs_-_OID_and_UUID "How do you create an OID ?" -The generated UUID will use the first 16 octet (128 bit) from the hash value. The UUID is a type 4 with a variant 1. See below the pseudo-code to ensure the type and the variant are correct in the UUID: +The generated UUID will use the first 16 octet (128 bit) from the hash value. The UUID is a type 4 +with a variant 1. See below the pseudo-code to ensure the type and the variant are correct in the +UUID: ``` // Version @@ -89,7 +135,8 @@ uuid[8] &= 0x3F uuid[8] != 0x80 ``` -The hashed value will be converted in a positive decimal and added at the root of the OID separated by a dot. See the example below: +The hashed value will be converted in a positive decimal and added at the root of the OID separated +by a dot. See the example below: ``` OID_ROOT = “2.25” @@ -98,13 +145,19 @@ uuid = OID_ROOT + “.” + HashedValue[0:16].toPositiveDecimal() ## Shift Date, Generate a random date -KARNAK offer the possibility of shifting a date randomly. This shift must be the same in the context of the project and **for the patient**. For example, if a random shift is made for the birthdate of the patient "José Santos", it must be the same for each instance associate to "José Santos", even if the instance is loaded later. +KARNAK offer the possibility of shifting a date randomly. This shift must be the same in the context +of the project and **for the patient**. For example, if a random shift is made for the birthdate of +the patient "José Santos", it must be the same for each instance associate to "José Santos", even if +the instance is loaded later. -The random shift date will use the HMAC defined above and a scale days or seconds given by the user. If the scaled minimum isn't given, it will be set to 0. +The random shift date will use the HMAC defined above and a scale days or seconds given by the user. +If the scaled minimum isn't given, it will be set to 0. -As the HMAC needs a value for the hash, the patientID will be used to ensure date consistency by patient. +As the HMAC needs a value for the hash, the patientID will be used to ensure date consistency by +patient. -See the code below to show how KARNAK will generate a random value between a minimum (inclusive) and maximum (exclusive) given. +See the code below to show how KARNAK will generate a random value between a minimum (inclusive) and +maximum (exclusive) given. ``` scaleHash(PatientID, scaledMin, scaledMax): @@ -116,49 +169,78 @@ scaleHash(PatientID, scaledMin, scaledMax): ## Pseudonym -This chapter will explain the problem with a pseudonym defined for different de-identifications method, how KARNAK generated a PatientID per project and where the pseudonym will be stored in the DICOM study. +This chapter will explain the problem with a pseudonym defined for different de-identifications +method, how KARNAK generated a PatientID per project and where the pseudonym will be stored in the +DICOM study. -To allow a patient to participate in several studies requiring different de-identification, KARNAK generates a PatientID depending on the context. +To allow a patient to participate in several studies requiring different de-identification, KARNAK +generates a PatientID depending on the context. -Pseudonym generation is usually done for a patient, independent of de-identification. Depending on the project or the clinical research, the de-identification can ask to keep the year of birth or to delete it. There is a problem of consistency between pseudonymization and de-identification. In DICOM a patient is a module, like a block of metadata, the following link is the information module definition of the [Patient Modules](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.2.html). +Pseudonym generation is usually done for a patient, independent of de-identification. Depending on +the project or the clinical research, the de-identification can ask to keep the year of birth or to +delete it. There is a problem of consistency between pseudonymization and de-identification. In +DICOM a patient is a module, like a block of metadata, the following link is the information module +definition of +the [Patient Modules](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.2.html) +. -As shown in the Standard DICOM, the patient modules contains a lot of metadata about the information patient. In KARNAK, the patient won't be attached at only one definition of his metadata. +As shown in the Standard DICOM, the patient modules contains a lot of metadata about the information +patient. In KARNAK, the patient won't be attached at only one definition of his metadata. -The following illustration show the problem with the patient module. A patient send a DICOM study to be de-identified twice. The first de-identification will remove the patient birth date (*3. apply Project 1*) and the second will keep it (*5. apply Project 2*) . The PatientID won't be generated by KARNAK, but will be the pseudonym given. As illustrated the Patient Module will be shared with the two DICOM study because the PatientID is the same. Depending to the Picture Archiving and Communication System (PACS) the patient module will be updated with new value or not. +The following illustration show the problem with the patient module. A patient send a DICOM study to +be de-identified twice. The first de-identification will remove the patient birth date (*3. apply +Project 1*) and the second will keep it (*5. apply Project 2*) . The PatientID won't be generated +by KARNAK, but will be the pseudonym given. As illustrated the Patient Module will be shared with +the two DICOM study because the PatientID is the same. Depending to the Picture Archiving and +Communication System (PACS) the patient module will be updated with new value or not. ![](img/pseudonymization_karnak.png) - - -The second illustration show the same de-identification for the patient, but the KARNAK will generate a PatientID associated to the project. With this PatientID generated the patient module will be shared with the DICOM study who have been de-identified by the same project. The generation of the PatientID will be explain below, see chapter **PatientID generation**. +The second illustration show the same de-identification for the patient, but the KARNAK will +generate a PatientID associated to the project. With this PatientID generated the patient module +will be shared with the DICOM study who have been de-identified by the same project. The generation +of the PatientID will be explain below, see chapter **PatientID generation**. ![](img/pseudonymization_patientIDGenerated_karnak.png) ### PatientID generation -KARNAK will generate a Patient ID to resolve the problem explain above. The Patient ID generated will use the HMAC function defined in the context of a project, see chapter **Action U, Generate a new UID** for more details about the project and the HMAC function. +KARNAK will generate a Patient ID to resolve the problem explain above. The Patient ID generated +will use the HMAC function defined in the context of a project, see chapter **Action U, Generate a +new UID** for more details about the project and the HMAC function. -The Pseudonym given will be hashed and convert to hexadecimal to be used as Patient ID for the study DICOM de-identified. +The Pseudonym given will be hashed and convert to hexadecimal to be used as Patient ID for the study +DICOM de-identified. -The generated Patient ID will use the first 16 octet (128 bit) from the hashed pseudonym. The hashed pseudonym will be converted in a positive decimal and in hexadecimal. +The generated Patient ID will use the first 16 octet (128 bit) from the hashed pseudonym. The hashed +pseudonym will be converted in a positive decimal and in hexadecimal. -The hexadecimal generated from the pseudonym hashed will be used for the attributes Patient ID and for the Patient Name (In case the user has not defined to use the pseudonym as Patient Name). +The hexadecimal generated from the pseudonym hashed will be used for the attributes Patient ID and +for the Patient Name (In case the user has not defined to use the pseudonym as Patient Name). ### Keep the correspondence between pseudonym and patient -This part will explain which tags will be used to keep the correspondence between the pseudonym given and the patient. It's important for the user to know where he needs to look this information in the event that he needs to find the real patient. +This part will explain which tags will be used to keep the correspondence between the pseudonym +given and the patient. It's important for the user to know where he needs to look this information +in the event that he needs to find the real patient. -As explained above, the Patient ID in the DICOM study de-identified won't be the pseudonym but will a hexadecimal generated from the pseudonym hashed. This ID does not allow the patient to be found in the patient / pseudonym correspondence table. +As explained above, the Patient ID in the DICOM study de-identified won't be the pseudonym but will +a hexadecimal generated from the pseudonym hashed. This ID does not allow the patient to be found in +the patient / pseudonym correspondence table. The pseudonym will be stored in the attribute **Clinical Trial Subject ID** **(0012,0040)** #### Clinical Trial Subect ID -"*The Clinical Trial Subject ID (0012,0040) identifies the subject within the investigational protocol specified by Clinical Trial Protocol ID (0012,0020).*" [3] +"*The Clinical Trial Subject ID (0012,0040) identifies the subject within the investigational +protocol specified by Clinical Trial Protocol ID (0012,0020).*" [3] [3]: http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.html#sect_C.7.1.3.1.6 -The attribute *ClinicalTrialSubjectID* comes from the module [*Clinical Trial Subject Module*](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.html#sect_C.7.1.3). To avoid generating invalid DICOMs, other attributes will be added for this module to be valid, see *Clinical Trial Subject Module* below. +The attribute *ClinicalTrialSubjectID* comes from the module [*Clinical Trial Subject +Module*](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.html#sect_C.7.1.3) +. To avoid generating invalid DICOMs, other attributes will be added for this module to be valid, +see *Clinical Trial Subject Module* below. ## Attributes added by KARNAK @@ -166,20 +248,28 @@ This chapter explains which attributes are added by KARNAK during de-identificat ### Patient Module -This section lists the attributes changed or added by KARNAK in the [Patient Module](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.html#sect_C.7.1.1). The way the Patient ID is generated is explained above in the *Pseudonym* chapter. +This section lists the attributes changed or added by KARNAK in +the [Patient Module](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.html#sect_C.7.1.1) +. The way the Patient ID is generated is explained above in the *Pseudonym* chapter. -* **Patient ID (0010,0020)**, this attribute will contain a **hexadecimal generated from the pseudonym hashed**. +* **Patient ID (0010,0020)**, this attribute will contain a **hexadecimal generated from the + pseudonym hashed**. -* **Patient Name (0010,0010)** this attribute will contain the value of the **PatientID or the pseudonym**. (This choice is defined by the user) +* **Patient Name (0010,0010)** this attribute will contain the value of the **PatientID or the + pseudonym**. (This choice is defined by the user) * **Patient Identity Removed (0012,0062)** this attribute will contain the value **YES** * **De-identification Method (0012,0063)** this attribute will contain the **profile pipe codename** -The profile pipe codename, is the codenames used in a profile concatenated by a "-". For example the profile that use the profile codename *clean.pixel.data* and *basic.dicom.profile*, the profile pipe codename will be *clean.pixel.data-basic.dicom.profile*. +The profile pipe codename, is the codenames used in a profile concatenated by a "-". For example the +profile that use the profile codename *clean.pixel.data* and *basic.dicom.profile*, the profile pipe +codename will be *clean.pixel.data-basic.dicom.profile*. ### Clinical Trial Subject Module -This section will explain how KARNAK defined the attributes in the [*Clinical Trial Subject Module*](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.html#sect_C.7.1.3). +This section will explain how KARNAK defined the attributes in the [*Clinical Trial Subject +Module*](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.html#sect_C.7.1.3) +. The following list, is the attribute added by KARNAK: @@ -188,9 +278,11 @@ The following list, is the attribute added by KARNAK: * **Clinical Trial Protocol Name (0012,0021**), required, empty if unknown * **Clinical Trial Site ID (0012,0030)**, required, empty if unknown * **Clinical Trial Site Name (0012,0031)**, required, empty if unknown -* **Clinical Trial Subject ID (0012,0040)**, shall be present if Clinical Trial Subject Reading ID (0012,0042) is absent. +* **Clinical Trial Subject ID (0012,0040)**, shall be present if Clinical Trial Subject Reading ID ( + 0012,0042) is absent. -In the near future this list of attributes could be managed by the user when initializing or editing a project, except for *Clinical Trial Subject ID* that will always contains the pseudonym. +In the near future this list of attributes could be managed by the user when initializing or editing +a project, except for *Clinical Trial Subject ID* that will always contains the pseudonym. But currently these values are automatically filled in by KARNAK as below. @@ -201,7 +293,9 @@ But currently these values are automatically filled in by KARNAK as below. * Clinical Trial Site Name (0012,0031) will contain ***null*** * Clinical Trial Subject ID (0012,0040) will contain the **pseudonym**. -The profile pipe codename, is the codenames used in a profile concatenated by a "-". For example the profile that use the profile codename *clean.pixel.data* and *basic.dicom.profile*, the profile pipe codename will be *clean.pixel.data-basic.dicom.profile*. +The profile pipe codename, is the codenames used in a profile concatenated by a "-". For example the +profile that use the profile codename *clean.pixel.data* and *basic.dicom.profile*, the profile pipe +codename will be *clean.pixel.data-basic.dicom.profile*. diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 88fd8aad7..d7e6d5079 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -3,29 +3,38 @@ version: '3.7' services: karnak: image: repo-docker.hcuge.ch:9082/karnak:${SERVICE_VERSION} - environment: - JAVA_OPTS: -XX:MaxRAM=512m -XX:MaxRAMPercentage=75 -XX:+UseContainerSupport -XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=162M - KARNAK_WAIT_FOR: karnak-db:5432 - env_file: karnak.env - depends_on: - - karnak-db + # environment: + # JAVA_OPTS: -XX:MaxRAM=512m -XX:MaxRAMPercentage=75 -XX:+UseContainerSupport -XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=162M + # KARNAK_WAIT_FOR: karnak-db:5432 + # env_file: karnak.env + # depends_on: + # - karnak-db karnak-db: image: repo-docker.hcuge.ch:9082/postgres:hug-9.6-alpine - environment: - - POSTGRES_DB=karnak - - POSTGRES_USER=karnak - - POSTGRES_PASSWORD=H2srvXJcHbBUhBafn2BK5I9oSbaQ1rw8697V8ESs/2o= + # environment: + # - POSTGRES_DB=karnak + # - POSTGRES_USER=karnak + # - POSTGRES_PASSWORD=H2srmXJbHaBUhBafn2BK5I9oSbaQ1rw8697V8ESs/2o= mainzelliste-db: image: repo-docker.hcuge.ch:9082/postgres:hug-9.6-alpine - environment: - - POSTGRES_DB=mainzelliste - - POSTGRES_USER=mainzelliste - - POSTGRES_PASSWORD=LCqWpeyJi6uStLdJq93tD+NHxJ+yVYDgOknet5slIIk= + # environment: + # - POSTGRES_DB=mainzelliste + # - POSTGRES_USER=mainzelliste + # - POSTGRES_PASSWORD=LCqWpeyJi6uStLdIq98tD+NHvJ+yVYDgOknet5slIIk= mainzelliste: image: repo-docker.hcuge.ch:9082/osirixfoundation/karnak-mainzelliste:extid - env_file: mainzelliste.env - depends_on: - - mainzelliste-db + # env_file: mainzelliste.env + # depends_on: + # - mainzelliste-db + + karnak-cache: + image: repo-docker.hcuge.ch:9082/redis:6.0.16-alpine3.15 + + db-backup: + image: repo-docker.hcuge.ch:9082/pqsql-backup-s3:2.0 + + mainzelliste-db-backup: + image: repo-docker.hcuge.ch:9082/pqsql-backup-s3:2.0 \ No newline at end of file diff --git a/frontend/styles/shared-styles.css b/frontend/styles/shared-styles.css index 9ef5a4d2e..a36eb7b95 100644 --- a/frontend/styles/shared-styles.css +++ b/frontend/styles/shared-styles.css @@ -167,5 +167,6 @@ label[disabled] { --vaadin-text-field-default-width: 6em; } } + /**/ /**/ \ No newline at end of file diff --git a/pom.xml b/pom.xml index 07d94d2e0..867ecce69 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ - 1.0.3-RELEASE + 1.0.49-RELEASE jar @@ -27,12 +27,12 @@ UTF-8 [${java.version},) [3.2.0,) - 15 + 17 2.6.6 3.0.0 1.6.2 21.0.9 - 5.25.1.1-IMG-RELEASE + 5.27.0.1 4.5.5-dcm 1.6.0 4.2.0 @@ -45,11 +45,11 @@ ${java.version} ${java.version} karnak - ${project.basedir}/target/site/jacoco/jacoco.xml + ${project.basedir}/target/site/jacoco/jacoco.xml + jacoco 20211205 1.2.9 - 5.1.1 4.3.5 5.5.2 @@ -73,7 +73,7 @@ HUG_Nexus3 Nexus3-hug - http://nxrm.hcuge.ch:8091/repository/maven-public/ + https://nxrm.hisaas.hcuge.ch/repository/maven-public/ default true @@ -91,9 +91,7 @@ www.dcm4che.org dcm4che Repository - http://maven.dcm4che.org - + https://www.dcm4che.org/maven2 @@ -313,14 +311,14 @@ - - - - - - - - + + + + + + + + @@ -380,17 +378,30 @@ spring-boot-starter-thymeleaf + + org.springframework.boot + spring-boot-starter-cache + + + + org.springframework.boot + spring-boot-starter-data-redis + + cache-api javax.cache 1.1.1 - - com.hazelcast - hazelcast-spring - ${hazelcast.version} + org.springframework.cloud + spring-cloud-starter + true + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client @@ -687,6 +698,14 @@ pom ${vaadin.version} + + + org.springframework.cloud + spring-cloud-dependencies + 2021.0.2 + pom + import + diff --git a/src/main/docker/Dockerfile b/src/main/docker/Dockerfile index 458f0985b..1a5863b58 100644 --- a/src/main/docker/Dockerfile +++ b/src/main/docker/Dockerfile @@ -2,16 +2,18 @@ # # docker build -t osirixfoundation/karnak:latest -f src/main/docker/Dockerfile . + # Based on build image containing maven, jdk and git -FROM maven:3.6-adoptopenjdk-15 as builder +FROM maven:3.6-openjdk-17 as builder ARG JAR_FILE=target/karnak*.jar WORKDIR /app COPY ${JAR_FILE} application.jar RUN java -Djarmode=layertools -jar application.jar extract # Build the final deployment image -FROM adoptopenjdk:15-jre-hotspot +FROM eclipse-temurin:17-jdk-jammy WORKDIR app + COPY --from=builder /app/dependencies/ ./ RUN true COPY --from=builder /app/spring-boot-loader/ ./ diff --git a/src/main/java/org/karnak/StartApplication.java b/src/main/java/org/karnak/StartApplication.java index 9cb49ac9d..612bec44e 100644 --- a/src/main/java/org/karnak/StartApplication.java +++ b/src/main/java/org/karnak/StartApplication.java @@ -46,11 +46,13 @@ public static void main(String[] args) { // application-oidc.yml if (System.getenv().containsKey(EnvironmentVariable.IDP.getCode()) && Objects.equals( - System.getenv().get(EnvironmentVariable.IDP.getCode()), - ApplicationProfile.OIDC.getCode())) { + System.getenv().get(EnvironmentVariable.IDP.getCode()), + ApplicationProfile.OIDC.getCode())) { application.profiles(ApplicationProfile.OIDC.getCode()); } + System.setProperty("spring.devtools.restart.enabled", "false"); + // Run application application.run(args); } diff --git a/src/main/java/org/karnak/backend/api/EchoServlet.java b/src/main/java/org/karnak/backend/api/EchoServlet.java index 816f6dc1d..2de282a2c 100644 --- a/src/main/java/org/karnak/backend/api/EchoServlet.java +++ b/src/main/java/org/karnak/backend/api/EchoServlet.java @@ -37,10 +37,13 @@ @WebServlet(urlPatterns = "/echo") public class EchoServlet extends HttpServlet { - @Serial private static final long serialVersionUID = -8349040600894140520L; + @Serial + private static final long serialVersionUID = -8349040600894140520L; + private static final Logger LOGGER = LoggerFactory.getLogger(EchoServlet.class); - @Autowired private GatewaySetUpService globalConfig; + @Autowired + private GatewaySetUpService globalConfig; @Override public final void init() throws ServletException { diff --git a/src/main/java/org/karnak/backend/api/KheopsApi.java b/src/main/java/org/karnak/backend/api/KheopsApi.java index 6f5895db8..fd621c764 100644 --- a/src/main/java/org/karnak/backend/api/KheopsApi.java +++ b/src/main/java/org/karnak/backend/api/KheopsApi.java @@ -31,6 +31,7 @@ public class KheopsApi { private final HttpClient httpClient; + private final String X_AUTHORIZATION_SOURCE = "X-Authorization-Source"; private static final Logger LOGGER = LoggerFactory.getLogger(KheopsApi.class); diff --git a/src/main/java/org/karnak/backend/api/PseudonymApi.java b/src/main/java/org/karnak/backend/api/PseudonymApi.java index aabfcd4b9..26afedb22 100644 --- a/src/main/java/org/karnak/backend/api/PseudonymApi.java +++ b/src/main/java/org/karnak/backend/api/PseudonymApi.java @@ -36,15 +36,19 @@ import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; -/** API model */ +/** + * API model + */ public class PseudonymApi { private static final Logger LOGGER = LoggerFactory.getLogger(PseudonymApi.class); private static final String SERVER_URL = MainzellisteConfig.getInstance().getServerurl(); + private static final String API_KEY = MainzellisteConfig.getInstance().getApikey(); private static final String MAINZELLISTE_HEADER = "mainzellisteApiKey"; + private static final String CONTENT_TYPE_HEADER = "Content-Type"; private final HttpClient httpClient = @@ -113,11 +117,10 @@ private String getPseudonym(Data data) throws IOException { } /*** - * This classe allow the communcation betwen karnak and pseudonym api with a specific sessionId - * @param sessionsId - * public PseudonymApi(String sessionsId) { - * this.sessionId = sessionsId; - * } + * This classe allow the communcation betwen karnak and pseudonym api with a specific + * sessionId + * @param sessionsId public PseudonymApi(String sessionsId) { this.sessionId = + * sessionsId; } */ /*** @@ -306,8 +309,9 @@ private JSONArray rqGetPatient(String tokenId, boolean shouldThrowException) */ private String createJsonReadPatient(SearchIds[] searchIds) { String[] resultFields = { - "patientID", "patientName", "patientBirthDate", "patientSex", "issuerOfPatientID" - }; // fields returns + "patientID", "patientName", "patientBirthDate", "patientSex", "issuerOfPatientID" + }; // fields + // returns Data data = new Data(searchIds, resultFields); Body bodyRequest = new Body("readPatients", data); @@ -318,7 +322,7 @@ private String createJsonReadPatient(SearchIds[] searchIds) { /** * Control response * - * @param response Response + * @param response Response * @param throwError should an exception should be thrown * @return true if no problem in response, false otherwise */ diff --git a/src/main/java/org/karnak/backend/api/rqbody/Body.java b/src/main/java/org/karnak/backend/api/rqbody/Body.java index 8c7c342cb..6109d972e 100644 --- a/src/main/java/org/karnak/backend/api/rqbody/Body.java +++ b/src/main/java/org/karnak/backend/api/rqbody/Body.java @@ -12,6 +12,7 @@ public class Body { private String type; + private Data data; public Body(String type, Data data) { diff --git a/src/main/java/org/karnak/backend/api/rqbody/Data.java b/src/main/java/org/karnak/backend/api/rqbody/Data.java index a2a16c880..0f8591ee5 100644 --- a/src/main/java/org/karnak/backend/api/rqbody/Data.java +++ b/src/main/java/org/karnak/backend/api/rqbody/Data.java @@ -12,10 +12,15 @@ public class Data { private String[] idtypes; + private Fields fields; + private Ids ids; + private SearchIds[] searchIds; + private String[] resultFields; + private String[] resultIds; public Data(String[] idtypes, Fields fields, Ids ids) { diff --git a/src/main/java/org/karnak/backend/api/rqbody/Fields.java b/src/main/java/org/karnak/backend/api/rqbody/Fields.java index 2f4aab32e..491aadcdb 100644 --- a/src/main/java/org/karnak/backend/api/rqbody/Fields.java +++ b/src/main/java/org/karnak/backend/api/rqbody/Fields.java @@ -12,16 +12,20 @@ public class Fields { // --------------------------------------------------------------- - // Fields ------------------------------------------------------- + // Fields ------------------------------------------------------- // --------------------------------------------------------------- private String patientID; + private String patientName; + private String patientBirthDate; + private String patientSex; + private String issuerOfPatientID; // --------------------------------------------------------------- - // Constructors ------------------------------------------------ + // Constructors ------------------------------------------------ // --------------------------------------------------------------- public Fields(String patientID) { this.patientID = patientID; @@ -41,7 +45,7 @@ public Fields( } // --------------------------------------------------------------- - // Getters/Setters ------------------------------------------------ + // Getters/Setters ------------------------------------------------ // --------------------------------------------------------------- public String get_patientID() { return this.patientID; diff --git a/src/main/java/org/karnak/backend/api/rqbody/SearchIds.java b/src/main/java/org/karnak/backend/api/rqbody/SearchIds.java index 7d7cc3c92..9e91fd4c5 100644 --- a/src/main/java/org/karnak/backend/api/rqbody/SearchIds.java +++ b/src/main/java/org/karnak/backend/api/rqbody/SearchIds.java @@ -12,6 +12,7 @@ public class SearchIds { private String idType; + private String idString; public SearchIds(String idType, String idString) { diff --git a/src/main/java/org/karnak/backend/cache/CachedPatient.java b/src/main/java/org/karnak/backend/cache/CachedPatient.java deleted file mode 100644 index 6e37f739f..000000000 --- a/src/main/java/org/karnak/backend/cache/CachedPatient.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2020-2021 Karnak Team and other contributors. - * - * This program and the accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at https://www.eclipse.org/legal/epl-2.0, or the Apache - * License, Version 2.0 which is available at https://www.apache.org/licenses/LICENSE-2.0. - * - * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 - */ -package org.karnak.backend.cache; - -public class CachedPatient extends Patient { - - private Long projectID; - - public CachedPatient( - String pseudonym, - String patientId, - String patientFirstName, - String patientLastName, - String issuerOfPatientId, - Long projectID) { - super(pseudonym, patientId, patientFirstName, patientLastName, null, null, issuerOfPatientId); - this.projectID = projectID; - } - - public void setPseudonym(String pseudonym) { - this.pseudonym = pseudonym; - } - - public void setPatientId(String patientId) { - this.patientId = patientId; - } - - public void setPatientFirstName(String patientFirstName) { - updatePatientFirstName(patientFirstName); - } - - public void setPatientLastName(String patientLastName) { - updatePatientLastName(patientLastName); - } - - public void setIssuerOfPatientId(String issuerOfPatientId) { - this.issuerOfPatientId = issuerOfPatientId; - } - - public Long getProjectID() { - return projectID; - } - - public void setProjectID(Long projectID) { - this.projectID = projectID; - } - - @Override - public String toString() { - return String.format( - "External pseudonym: %s, Patient ID: %s, Patient first name: %s, Patient last name: %s," - + " Issuer of patient ID: %s", - pseudonym, patientId, patientFirstName, patientLastName, issuerOfPatientId); - } -} diff --git a/src/main/java/org/karnak/backend/cache/ExternalIDCache.java b/src/main/java/org/karnak/backend/cache/ExternalIDCache.java index 7bd313c3b..4372251ee 100644 --- a/src/main/java/org/karnak/backend/cache/ExternalIDCache.java +++ b/src/main/java/org/karnak/backend/cache/ExternalIDCache.java @@ -9,15 +9,17 @@ */ package org.karnak.backend.cache; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; @Component public class ExternalIDCache extends PatientClient { - private static final String NAME = "externalid"; - private static final int TTL_SECONDS = 60 * 60 * 24 * 7; + private static final String NAME = "externalId.cache"; - public ExternalIDCache() { - super(NAME, TTL_SECONDS); + public ExternalIDCache( + RedisCacheManager redisCacheManager, RedisTemplate redisTemplate) { + super(redisCacheManager.getCache(NAME), redisTemplate, NAME); } } diff --git a/src/main/java/org/karnak/backend/cache/MainzellisteCache.java b/src/main/java/org/karnak/backend/cache/MainzellisteCache.java index 120f2791d..abc8141b5 100644 --- a/src/main/java/org/karnak/backend/cache/MainzellisteCache.java +++ b/src/main/java/org/karnak/backend/cache/MainzellisteCache.java @@ -9,15 +9,17 @@ */ package org.karnak.backend.cache; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; @Component public class MainzellisteCache extends PatientClient { - private static final String NAME = "mainzelliste"; - private static final int TTL_SECONDS = 15 * 60; + private static final String NAME = "mainzelliste.cache"; - public MainzellisteCache() { - super(NAME, TTL_SECONDS); + public MainzellisteCache( + RedisCacheManager redisCacheManager, RedisTemplate redisTemplate) { + super(redisCacheManager.getCache(NAME), redisTemplate, NAME); } } diff --git a/src/main/java/org/karnak/backend/cache/MainzellistePatient.java b/src/main/java/org/karnak/backend/cache/MainzellistePatient.java deleted file mode 100644 index fab48da9c..000000000 --- a/src/main/java/org/karnak/backend/cache/MainzellistePatient.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2020-2021 Karnak Team and other contributors. - * - * This program and the accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at https://www.eclipse.org/legal/epl-2.0, or the Apache - * License, Version 2.0 which is available at https://www.apache.org/licenses/LICENSE-2.0. - * - * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 - */ -package org.karnak.backend.cache; - -import java.time.LocalDate; - -public class MainzellistePatient extends Patient { - - public MainzellistePatient( - String pseudonym, - String patientId, - String patientFirstName, - String patientLastName, - LocalDate patientBirthDate, - String patientSex, - String issuerOfPatientId) { - super( - pseudonym, - patientId, - patientFirstName, - patientLastName, - patientBirthDate, - patientSex, - issuerOfPatientId); - } - - public void setPseudonym(String pseudonym) { - this.pseudonym = pseudonym; - } - - public void setPatientId(String patientId) { - this.patientId = patientId; - } - - public void setPatientFirstName(String patientFirstName) { - updatePatientFirstName(patientFirstName); - } - - public void setPatientLastName(String patientLastName) { - updatePatientLastName(patientLastName); - } - - public void setPatientBirthDate(LocalDate patientBirthDate) { - this.patientBirthDate = patientBirthDate; - } - - public void setPatientSex(String patientSex) { - this.patientSex = patientSex; - } - - public void setIssuerOfPatientId(String issuerOfPatientId) { - this.issuerOfPatientId = issuerOfPatientId; - } -} diff --git a/src/main/java/org/karnak/backend/cache/Patient.java b/src/main/java/org/karnak/backend/cache/Patient.java index a2e2caf79..85cd577ed 100644 --- a/src/main/java/org/karnak/backend/cache/Patient.java +++ b/src/main/java/org/karnak/backend/cache/Patient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021 Karnak Team and other contributors. + * Copyright (c) 2022 Karnak Team and other contributors. * * This program and the accompanying materials are made available under the terms of the Eclipse * Public License 2.0 which is available at https://www.eclipse.org/legal/epl-2.0, or the Apache @@ -9,39 +9,65 @@ */ package org.karnak.backend.cache; +import java.io.Serial; import java.io.Serializable; import java.time.LocalDate; -public abstract class Patient implements PseudonymPatient, Serializable { +public class Patient implements Serializable { + + @Serial + private static final long serialVersionUID = -6906583906530083181L; private static final Character SPLIT_CHAR_PATIENT_NAME = '^'; - protected String pseudonym; - protected String patientId; - protected String patientName; - protected String patientFirstName; - protected String patientLastName; - protected LocalDate patientBirthDate; - protected String patientSex; - protected String issuerOfPatientId; - - protected Patient( + + private String pseudonym; + private String patientId; + private String patientName; + private String patientFirstName; + private String patientLastName; + private LocalDate patientBirthDate; + private String patientSex; + private String issuerOfPatientId; + private Long projectID; + + public Patient( String pseudonym, String patientId, String patientName, + String patientFirstName, + String patientLastName, LocalDate patientBirthDate, String patientSex, - String issuerOfPatientId) { + String issuerOfPatientId, + Long projectID) { this.pseudonym = pseudonym; this.patientId = patientId; this.patientName = patientName; - this.patientFirstName = createPatientFirstName(patientName); - this.patientLastName = createPatientLastName(patientName); + this.patientFirstName = emptyStringIfNull(patientFirstName); + this.patientLastName = emptyStringIfNull(patientLastName); this.patientBirthDate = patientBirthDate; this.patientSex = patientSex; this.issuerOfPatientId = issuerOfPatientId; + this.projectID = projectID; + } + + public Patient( + String pseudonym, + String patientId, + String patientFirstName, + String patientLastName, + String issuerOfPatientId, + Long projectID) { + this.pseudonym = pseudonym; + this.patientId = patientId; + this.patientFirstName = emptyStringIfNull(patientFirstName); + this.patientLastName = emptyStringIfNull(patientLastName); + this.patientName = createPatientName(patientFirstName, patientLastName); + this.issuerOfPatientId = issuerOfPatientId; + this.projectID = projectID; } - protected Patient( + public Patient( String pseudonym, String patientId, String patientFirstName, @@ -51,25 +77,84 @@ protected Patient( String issuerOfPatientId) { this.pseudonym = pseudonym; this.patientId = patientId; - this.patientName = createPatientName(patientFirstName, patientLastName); this.patientFirstName = emptyStringIfNull(patientFirstName); this.patientLastName = emptyStringIfNull(patientLastName); + this.patientName = createPatientName(patientFirstName, patientLastName); + this.issuerOfPatientId = issuerOfPatientId; this.patientBirthDate = patientBirthDate; this.patientSex = patientSex; + } + + public String getPseudonym() { + return pseudonym; + } + + public void setPseudonym(String pseudonym) { + this.pseudonym = pseudonym; + } + + public String getPatientId() { + return patientId; + } + + public void setPatientId(String patientId) { + this.patientId = patientId; + } + + public String getPatientName() { + return patientName; + } + + public void setPatientName(String patientName) { + this.patientName = patientName; + } + + public String getPatientFirstName() { + return patientFirstName; + } + + public void setPatientFirstName(String patientFirstName) { + this.patientFirstName = patientFirstName; + } + + public String getPatientLastName() { + return patientLastName; + } + + public void setPatientLastName(String patientLastName) { + this.patientLastName = patientLastName; + } + + public LocalDate getPatientBirthDate() { + return patientBirthDate; + } + + public void setPatientBirthDate(LocalDate patientBirthDate) { + this.patientBirthDate = patientBirthDate; + } + + public String getPatientSex() { + return patientSex; + } + + public void setPatientSex(String patientSex) { + this.patientSex = patientSex; + } + + public String getIssuerOfPatientId() { + return issuerOfPatientId; + } + + public void setIssuerOfPatientId(String issuerOfPatientId) { this.issuerOfPatientId = issuerOfPatientId; } - protected static String createPatientLastName(String patientName) { - return patientName.split(String.format("\\%c", SPLIT_CHAR_PATIENT_NAME))[0]; + public Long getProjectID() { + return projectID; } - protected static String createPatientFirstName(String patientName) { - String[] patientNameSplitted = - patientName.split(String.format("\\%c", SPLIT_CHAR_PATIENT_NAME)); - if (patientNameSplitted.length > 1) { - return patientNameSplitted[1]; - } - return ""; + public void setProjectID(Long projectID) { + this.projectID = projectID; } protected static String createPatientName(String patientFirstName, String patientLastName) { @@ -81,8 +166,17 @@ protected static String createPatientName(String patientFirstName, String patien patientLastName == null ? "" : patientLastName, SPLIT_CHAR_PATIENT_NAME, patientFirstName); } - private static String emptyStringIfNull(String value) { - return value == null ? "" : value; + protected static String createPatientLastName(String patientName) { + return patientName.split(String.format("\\%c", SPLIT_CHAR_PATIENT_NAME))[0]; + } + + protected static String createPatientFirstName(String patientName) { + String[] patientNameSplitted = + patientName.split(String.format("\\%c", SPLIT_CHAR_PATIENT_NAME)); + if (patientNameSplitted.length > 1) { + return patientNameSplitted[1]; + } + return ""; } public void updatePatientName(String patientName) { @@ -91,51 +185,48 @@ public void updatePatientName(String patientName) { this.patientLastName = createPatientLastName(patientName); } - protected void updatePatientLastName(String patientLastName) { + public void updatePatientLastName(String patientLastName) { this.patientLastName = emptyStringIfNull(patientLastName); this.patientName = createPatientName(patientFirstName, patientLastName); } - protected void updatePatientFirstName(String patientFirstName) { + public void updatePatientFirstName(String patientFirstName) { this.patientFirstName = emptyStringIfNull(patientFirstName); this.patientName = createPatientName(patientFirstName, patientLastName); } - @Override - public String getPseudonym() { - return pseudonym; - } - - @Override - public String getPatientId() { - return patientId; - } - - @Override - public String getPatientName() { - return patientName; - } - - public String getPatientFirstName() { - return patientFirstName; - } - - public String getPatientLastName() { - return patientLastName; - } - - @Override - public LocalDate getPatientBirthDate() { - return patientBirthDate; - } - - @Override - public String getPatientSex() { - return patientSex; + private static String emptyStringIfNull(String value) { + return value == null ? "" : value; } @Override - public String getIssuerOfPatientId() { - return issuerOfPatientId; + public String toString() { + return "Patient{" + + "pseudonym='" + + pseudonym + + '\'' + + ", patientId='" + + patientId + + '\'' + + ", patientName='" + + patientName + + '\'' + + ", patientFirstName='" + + patientFirstName + + '\'' + + ", patientLastName='" + + patientLastName + + '\'' + + ", patientBirthDate=" + + patientBirthDate + + ", patientSex='" + + patientSex + + '\'' + + ", issuerOfPatientId='" + + issuerOfPatientId + + '\'' + + ", projectID=" + + projectID + + '}'; } } diff --git a/src/main/java/org/karnak/backend/cache/PatientClient.java b/src/main/java/org/karnak/backend/cache/PatientClient.java index 6c0dfbd8e..8073c872a 100644 --- a/src/main/java/org/karnak/backend/cache/PatientClient.java +++ b/src/main/java/org/karnak/backend/cache/PatientClient.java @@ -9,57 +9,57 @@ */ package org.karnak.backend.cache; -import com.hazelcast.config.Config; -import com.hazelcast.config.MapConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.map.IMap; import java.util.Collection; +import java.util.Objects; +import java.util.stream.Collectors; +import org.springframework.cache.Cache; +import org.springframework.cache.Cache.ValueWrapper; +import org.springframework.data.redis.core.RedisTemplate; public abstract class PatientClient { - // https://docs.hazelcast.org/docs/latest/manual/html-single/#cp-subsystem - private static final String CLUSTER_NAME = "PatientClient"; - private static final int CP_MEMBER = 3; - private final String name; - private final HazelcastInstance hazelcastInstance; + private final Cache cache; + private final RedisTemplate redisTemplate; + private static final String KEY_SEPARATOR = "::"; + private final String prefixKeySearchCache; + private final String patternSearchAllKeysCache; - public PatientClient(String name, int ttlSeconds) { - this.name = name; - this.hazelcastInstance = Hazelcast.newHazelcastInstance(createConfig(ttlSeconds)); + public PatientClient(Cache cache, RedisTemplate redisTemplate, String name) { + this.cache = cache; + this.redisTemplate = redisTemplate; + this.prefixKeySearchCache = "%s%s".formatted(name, KEY_SEPARATOR); + this.patternSearchAllKeysCache = "%s*".formatted(prefixKeySearchCache); } - private Config createConfig(int ttlSeconds) { - Config config = new Config(); - MapConfig mapConfig = new MapConfig(name); - mapConfig.setTimeToLiveSeconds(ttlSeconds); - // The method setMaxIdleSeconds defines how long the entry stays in the cache without being - // touched - // mapConfig.setMaxIdleSeconds(20); - config.addMapConfig(mapConfig); - config.setClusterName(CLUSTER_NAME); - config.getCPSubsystemConfig().setCPMemberCount(CP_MEMBER); - config.setClassLoader(PseudonymPatient.class.getClassLoader()); - return config; + public Patient put(String key, Patient patient) { + return (Patient) cache.putIfAbsent(key, patient); } - public PseudonymPatient put(String key, PseudonymPatient patient) { - IMap map = hazelcastInstance.getMap(name); - return map.putIfAbsent(key, patient); + public Patient get(String key) { + ValueWrapper valueFromCache = cache.get(key); + return valueFromCache != null ? (Patient) valueFromCache.get() : null; } - public PseudonymPatient get(String key) { - IMap map = hazelcastInstance.getMap(name); - return map.get(key); + public void remove(String key) { + cache.evictIfPresent(key); } - public void remove(String key) { - IMap map = hazelcastInstance.getMap(name); - map.remove(key); + public Collection getAll() { + return Objects.requireNonNull(redisTemplate.keys(patternSearchAllKeysCache)).stream() + .filter(Objects::nonNull) + .filter(c -> c.length() > prefixKeySearchCache.length()) + .map( + k -> { + ValueWrapper keyValue = cache.get(k.substring(prefixKeySearchCache.length())); + return keyValue != null ? (Patient) keyValue.get() : null; + }) + .collect(Collectors.toList()); } - public Collection getAll() { - IMap map = hazelcastInstance.getMap(name); - return map.values(); + public void removeAll() { + Objects.requireNonNull(redisTemplate.keys(patternSearchAllKeysCache)).stream() + .filter(Objects::nonNull) + .filter(c -> c.length() > prefixKeySearchCache.length()) + .forEach(k -> remove(k.substring(prefixKeySearchCache.length()))); } } diff --git a/src/main/java/org/karnak/backend/cache/PseudonymPatient.java b/src/main/java/org/karnak/backend/cache/PseudonymPatient.java deleted file mode 100644 index 2cd1bacb7..000000000 --- a/src/main/java/org/karnak/backend/cache/PseudonymPatient.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2020-2021 Karnak Team and other contributors. - * - * This program and the accompanying materials are made available under the terms of the Eclipse - * Public License 2.0 which is available at https://www.eclipse.org/legal/epl-2.0, or the Apache - * License, Version 2.0 which is available at https://www.apache.org/licenses/LICENSE-2.0. - * - * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 - */ -package org.karnak.backend.cache; - -import java.time.LocalDate; - -public interface PseudonymPatient { - String getPseudonym(); - - String getPatientId(); - - String getPatientName(); - - String getIssuerOfPatientId(); - - LocalDate getPatientBirthDate(); - - String getPatientSex(); -} diff --git a/src/main/java/org/karnak/backend/cache/RequestCache.java b/src/main/java/org/karnak/backend/cache/RequestCache.java index 5fce1abad..76a3c5100 100644 --- a/src/main/java/org/karnak/backend/cache/RequestCache.java +++ b/src/main/java/org/karnak/backend/cache/RequestCache.java @@ -24,7 +24,7 @@ public class RequestCache extends HttpSessionRequestCache { * Saves unauthenticated requests so we can redirect the user to the page they were trying to * access once they’re logged in * - * @param request Request + * @param request Request * @param response Response */ @Override diff --git a/src/main/java/org/karnak/backend/config/AppConfig.java b/src/main/java/org/karnak/backend/config/AppConfig.java index 8ddf9abb6..2f2e87799 100644 --- a/src/main/java/org/karnak/backend/config/AppConfig.java +++ b/src/main/java/org/karnak/backend/config/AppConfig.java @@ -28,6 +28,9 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; @@ -37,6 +40,9 @@ @Configuration @EnableConfigurationProperties @ConfigurationProperties +@EnableCaching +@EnableDiscoveryClient +@EnableEurekaClient public class AppConfig { private static final Logger LOGGER = LoggerFactory.getLogger(AppConfig.class); @@ -49,11 +55,19 @@ public class AppConfig { private final ProfileRepo profileRepo; private final ProfilePipeService profilePipeService; private String nameInstance; + private final ExternalIDCache externalIDCache; + private final MainzellisteCache mainzellisteCache; @Autowired - public AppConfig(final ProfileRepo profileRepo, final ProfilePipeService profilePipeService) { + public AppConfig( + final ProfileRepo profileRepo, + final ProfilePipeService profilePipeService, + final ExternalIDCache externalIDCache, + final MainzellisteCache mainzellisteCache) { this.profileRepo = profileRepo; this.profilePipeService = profilePipeService; + this.externalIDCache = externalIDCache; + this.mainzellisteCache = mainzellisteCache; } @PostConstruct @@ -105,12 +119,12 @@ public ConfidentialityProfiles getConfidentialityProfile() { @Bean("ExternalIDPatient") public PatientClient getExternalIDCache() { - return new ExternalIDCache(); + return externalIDCache; } @Bean("MainzellisteCache") public PatientClient getMainzellisteCache() { - return new MainzellisteCache(); + return mainzellisteCache; } // https://stackoverflow.com/questions/27405713/running-code-after-spring-boot-starts diff --git a/src/main/java/org/karnak/backend/config/EmailConfig.java b/src/main/java/org/karnak/backend/config/EmailConfig.java index 973860da1..751ab7eb8 100644 --- a/src/main/java/org/karnak/backend/config/EmailConfig.java +++ b/src/main/java/org/karnak/backend/config/EmailConfig.java @@ -35,6 +35,7 @@ public JavaMailSender getJavaMailSender() { mailSender.setPort(Integer.parseInt(mailSmtpPort)); mailSender.setUsername(mailSmtpUser); mailSender.setPassword(SystemPropertyUtil.retrieveSystemProperty("MAIL_SMTP_SECRET", null)); + mailSender.setDefaultEncoding("utf-8"); // Additional properties Properties props = mailSender.getJavaMailProperties(); @@ -45,8 +46,9 @@ public JavaMailSender getJavaMailSender() { props.put("mail.smtp.auth", "true"); if (Objects.equals("SSL", mailAuthType)) { props.put("mail.smtp.socketFactory.port", mailSmtpPort); // SSL Port - props.put( - "mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); // SSL Factory Class + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); // SSL + // Factory + // Class props.put("mail.smtp.ssl.checkserveridentity", true); } else { props.put("mail.smtp.starttls.enable", "true"); diff --git a/src/main/java/org/karnak/backend/config/MainzellisteConfig.java b/src/main/java/org/karnak/backend/config/MainzellisteConfig.java index 298c0cda6..f937b1bb8 100644 --- a/src/main/java/org/karnak/backend/config/MainzellisteConfig.java +++ b/src/main/java/org/karnak/backend/config/MainzellisteConfig.java @@ -20,8 +20,11 @@ public class MainzellisteConfig { private static MainzellisteConfig instance; + private String apikey; + private String serverurl; + private String idtypes; public static MainzellisteConfig getInstance() { diff --git a/src/main/java/org/karnak/backend/config/RedisConfiguration.java b/src/main/java/org/karnak/backend/config/RedisConfiguration.java new file mode 100644 index 000000000..f04395434 --- /dev/null +++ b/src/main/java/org/karnak/backend/config/RedisConfiguration.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 Karnak Team and other contributors. + * + * This program and the accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at https://www.eclipse.org/legal/epl-2.0, or the Apache + * License, Version 2.0 which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + */ +package org.karnak.backend.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.time.Duration; +import org.karnak.backend.cache.Patient; +import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +public class RedisConfiguration { + + @Bean + ChannelTopic topic() { + return new ChannelTopic("patient:queue"); + } + + @Bean(name = "redisTemplate") + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + + ObjectMapper objectMapper = + new ObjectMapper().registerModule(new Jdk8Module()).registerModule(new JavaTimeModule()); + + Jackson2JsonRedisSerializer serializer = + new Jackson2JsonRedisSerializer<>(Patient.class); + serializer.setObjectMapper(objectMapper); + + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(connectionFactory); + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(serializer); + + return template; + } + + @Bean + public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() { + return (builder) -> + builder + .withCacheConfiguration( + "externalId.cache", + RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(7))) + .withCacheConfiguration( + "mainzelliste.cache", + RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(15))); + } +} diff --git a/src/main/java/org/karnak/backend/config/SecurityInMemoryConfig.java b/src/main/java/org/karnak/backend/config/SecurityInMemoryConfig.java index 5d0b7627c..54d932779 100644 --- a/src/main/java/org/karnak/backend/config/SecurityInMemoryConfig.java +++ b/src/main/java/org/karnak/backend/config/SecurityInMemoryConfig.java @@ -13,6 +13,9 @@ import org.karnak.backend.enums.SecurityRole; import org.karnak.backend.security.DefaultIdpLoadCondition; import org.karnak.backend.util.SecurityUtil; +import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; +import org.springframework.boot.actuate.health.HealthEndpoint; +import org.springframework.boot.actuate.info.InfoEndpoint; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @@ -30,23 +33,31 @@ public class SecurityInMemoryConfig extends WebSecurityConfigurerAdapter { private static final String LOGIN_FAILURE_URL = "/login?error"; + private static final String LOGIN_URL = "/login"; @Override protected void configure(HttpSecurity http) throws Exception { http - // Uses RequestCache to track unauthorized requests so that users are redirected + // Uses RequestCache to track unauthorized requests so that users are + // redirected // appropriately after login .requestCache() .requestCache(new RequestCache()) - // Disables cross-site request forgery (CSRF) protection for main route and login + // Disables cross-site request forgery (CSRF) protection for main route + // and login .and() .csrf() .ignoringAntMatchers("/", LOGIN_URL) // Turns on authorization .and() .authorizeRequests() + // Actuator and health + .antMatchers("/actuator/**") + .permitAll() + .requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)) + .permitAll() // Allows all internal traffic from the Vaadin framework .requestMatchers(SecurityUtil::isFrameworkInternalRequest) .permitAll() diff --git a/src/main/java/org/karnak/backend/config/SecurityOpenIdConnectConfig.java b/src/main/java/org/karnak/backend/config/SecurityOpenIdConnectConfig.java index 49e98308e..01de8319d 100644 --- a/src/main/java/org/karnak/backend/config/SecurityOpenIdConnectConfig.java +++ b/src/main/java/org/karnak/backend/config/SecurityOpenIdConnectConfig.java @@ -18,6 +18,9 @@ import org.karnak.backend.security.OpenIdConnectLogoutHandler; import org.karnak.backend.util.SecurityUtil; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; +import org.springframework.boot.actuate.health.HealthEndpoint; +import org.springframework.boot.actuate.info.InfoEndpoint; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @@ -46,7 +49,8 @@ public class SecurityOpenIdConnectConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http - // Uses RequestCache to track unauthorized requests so that users are redirected + // Uses RequestCache to track unauthorized requests so that users are + // redirected // appropriately after login .requestCache() .requestCache(new RequestCache()) @@ -57,6 +61,11 @@ protected void configure(HttpSecurity http) throws Exception { // Turns on authorization .and() .authorizeRequests() + // Actuator and health + .antMatchers("/actuator/**") + .permitAll() + .requestMatchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)) + .permitAll() // Allows all internal traffic from the Vaadin framework .requestMatchers(SecurityUtil::isFrameworkInternalRequest) .permitAll() @@ -105,14 +114,14 @@ public void configure(WebSecurity web) { private Set retrieveRolesFromAccessToken(Jwt jwt) { // Build roles return ((List) - ((Map) - ((Map) jwt.getClaims().get(Token.RESOURCE_ACCESS)) - .get(Token.RESOURCE_NAME)) - .get(Token.ROLES)) + ((Map) + ((Map) jwt.getClaims().get(Token.RESOURCE_ACCESS)) + .get(Token.RESOURCE_NAME)) + .get(Token.ROLES)) .stream() - .map(roleName -> Token.PREFIX_ROLE + roleName) - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toSet()); + .map(roleName -> Token.PREFIX_ROLE + roleName) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toSet()); } /** diff --git a/src/main/java/org/karnak/backend/config/WebConfig.java b/src/main/java/org/karnak/backend/config/WebConfig.java index 114198f80..6f5083e07 100644 --- a/src/main/java/org/karnak/backend/config/WebConfig.java +++ b/src/main/java/org/karnak/backend/config/WebConfig.java @@ -14,7 +14,9 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -/** Configuration for the Spring MVC part */ +/** + * Configuration for the Spring MVC part + */ @Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { diff --git a/src/main/java/org/karnak/backend/constant/EndPoint.java b/src/main/java/org/karnak/backend/constant/EndPoint.java index 73b35a90b..da82d8e3b 100644 --- a/src/main/java/org/karnak/backend/constant/EndPoint.java +++ b/src/main/java/org/karnak/backend/constant/EndPoint.java @@ -13,12 +13,16 @@ public class EndPoint { // Paths public static final String ECHO_PATH = "/api/echo"; + public static final String DESTINATIONS_PATH = "/destinations"; - // public static final String FILE_PATH = "/file"; - // public static final String DOWNLOAD_SOPUID_PATH = "/download/aet/sopuid"; + + // public static final String FILE_PATH = "/file"; + // public static final String DOWNLOAD_SOPUID_PATH = "/download/aet/sopuid"; // Params public static final String SRC_AET_PARAM = "srcAet"; - // public static final String AET_PARAM = "aet"; - // public static final String SOP_UID_PARAM = "sopUid"; + + // public static final String AET_PARAM = "aet"; + // public static final String SOP_UID_PARAM = "sopUid"; + } diff --git a/src/main/java/org/karnak/backend/constant/Notification.java b/src/main/java/org/karnak/backend/constant/Notification.java index 391c8b2ca..f1e926826 100644 --- a/src/main/java/org/karnak/backend/constant/Notification.java +++ b/src/main/java/org/karnak/backend/constant/Notification.java @@ -9,29 +9,41 @@ */ package org.karnak.backend.constant; -/** Constants for notification */ +/** + * Constants for notification + */ public class Notification { // Default public static final String DEFAULT_SUBJECT_ERROR_PREFIX = "**ERROR**"; + public static final String DEFAULT_SUBJECT_PATTERN = "[Karnak Notification] %s %.30s"; + public static final String DEFAULT_SUBJECT_VALUES = "PatientID,StudyDescription"; + public static final String DEFAULT_INTERVAL = "45"; + public static final String MAIL_SMTP_SENDER = "karnak@kehops.online"; // Thymeleaf public static final String CONTEXT_THYMELEAF = "notif"; + public static final String TEMPLATE_THYMELEAF = "transferNotificationEmail"; // Separators public static final String COMMA_SEPARATOR = ","; + public static final String EMPTY_STRING = ""; + public static final String SPACE = " "; // PARAMS public static final String PARAM_STUDY_DATE = "StudyDate"; + public static final String PARAM_STUDY_INSTANCE_UID = "StudyInstanceUID"; + public static final String PARAM_STUDY_DESCRIPTION = "StudyDescription"; + public static final String PARAM_PATIENT_ID = "PatientID"; // Various diff --git a/src/main/java/org/karnak/backend/constant/Token.java b/src/main/java/org/karnak/backend/constant/Token.java index 998fb471d..c95601fa7 100644 --- a/src/main/java/org/karnak/backend/constant/Token.java +++ b/src/main/java/org/karnak/backend/constant/Token.java @@ -9,14 +9,20 @@ */ package org.karnak.backend.constant; -/** Constants dealing used for token management */ +/** + * Constants dealing used for token management + */ public class Token { + // Name of the resource in the access token for retrieving roles public static final String RESOURCE_NAME = "karnak"; + // Access token resource access public static final String RESOURCE_ACCESS = "resource_access"; + // Roles public static final String ROLES = "roles"; + // Prefix of built roles public static final String PREFIX_ROLE = "ROLE_"; } diff --git a/src/main/java/org/karnak/backend/controller/EchoController.java b/src/main/java/org/karnak/backend/controller/EchoController.java index a91e78ac2..d52cf8385 100644 --- a/src/main/java/org/karnak/backend/controller/EchoController.java +++ b/src/main/java/org/karnak/backend/controller/EchoController.java @@ -32,7 +32,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -/** Rest controller managing echo */ +/** + * Rest controller managing echo + */ @RestController @RequestMapping(EndPoint.ECHO_PATH) @Tag(name = "Echo", description = "API Endpoints for Echo") @@ -59,17 +61,17 @@ public EchoController(final EchoService echoService) { tags = "Echo") @ApiResponses( value = { - @ApiResponse( - responseCode = "200", - description = "Status and configured destinations found from an AeTitle", - content = - @Content( - schema = @Schema(implementation = DestinationEchos.class), - examples = - @ExampleObject( - name = "Example values status destinations", - value = SpringDocUtil.EXAMPLE_VALUES_STATUS_DESTINATIONS_ECHO))), - @ApiResponse(responseCode = "204", description = "No Content", content = @Content) + @ApiResponse( + responseCode = "200", + description = "Status and configured destinations found from an AeTitle", + content = + @Content( + schema = @Schema(implementation = DestinationEchos.class), + examples = + @ExampleObject( + name = "Example values status destinations", + value = SpringDocUtil.EXAMPLE_VALUES_STATUS_DESTINATIONS_ECHO))), + @ApiResponse(responseCode = "204", description = "No Content", content = @Content) }) /** * Retrieve the status of the configured destinations from the source AeTitle in parameter diff --git a/src/main/java/org/karnak/backend/controller/FileController.java b/src/main/java/org/karnak/backend/controller/FileController.java index 71b25c061..47c7a9409 100644 --- a/src/main/java/org/karnak/backend/controller/FileController.java +++ b/src/main/java/org/karnak/backend/controller/FileController.java @@ -28,46 +28,46 @@ // @RequestMapping(EndPoint.FILE_PATH) // public class FileController { // -// private static final Logger LOGGER = LoggerFactory.getLogger(FileController.class); +// private static final Logger LOGGER = LoggerFactory.getLogger(FileController.class); // -// // Services -// private final FileService fileService; +// // Services +// private final FileService fileService; // -// /** -// * Autowired constructor -// * -// * @param fileService Service managing files -// */ -// @Autowired -// public FileController(final FileService fileService) { -// this.fileService = fileService; -// } +// /** +// * Autowired constructor +// * +// * @param fileService Service managing files +// */ +// @Autowired +// public FileController(final FileService fileService) { +// this.fileService = fileService; +// } // -// /** -// * @param aet Aet to get files from -// * @param fileName File to download -// * @return if successful download the file otherwise display an error message -// */ -// @GetMapping( -// value = {EndPoint.DOWNLOAD_SOPUID_PATH}, -// produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE}) -// public ResponseEntity downloadSopUidFromAetT( -// @RequestParam(value = EndPoint.AET_PARAM) String aet, -// @RequestParam(value = EndPoint.SOP_UID_PARAM) String fileName) { -// byte[] file; +// /** +// * @param aet Aet to get files from +// * @param fileName File to download +// * @return if successful download the file otherwise display an error message +// */ +// @GetMapping( +// value = {EndPoint.DOWNLOAD_SOPUID_PATH}, +// produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE}) +// public ResponseEntity downloadSopUidFromAetT( +// @RequestParam(value = EndPoint.AET_PARAM) String aet, +// @RequestParam(value = EndPoint.SOP_UID_PARAM) String fileName) { +// byte[] file; // -// try { -// file = fileService.retrieveFileToDownload(aet, fileName); -// } catch (Exception e) { -// LOGGER.error("Unexpected exception when downloading", e); -// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) -// .body("Error when downloading the file: Internal server error => " + e.getMessage()); -// } +// try { +// file = fileService.retrieveFileToDownload(aet, fileName); +// } catch (Exception e) { +// LOGGER.error("Unexpected exception when downloading", e); +// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) +// .body("Error when downloading the file: Internal server error => " + e.getMessage()); +// } // -// return file == null -// ? ResponseEntity.notFound().build() -// : ResponseEntity.status(HttpStatus.OK) -// .header("Content-Disposition", "attachment; filename=\"" + fileName + "\"") -// .body(file); -// } +// return file == null +// ? ResponseEntity.notFound().build() +// : ResponseEntity.status(HttpStatus.OK) +// .header("Content-Disposition", "attachment; filename=\"" + fileName + "\"") +// .body(file); +// } // } diff --git a/src/main/java/org/karnak/backend/data/entity/ArgumentEntity.java b/src/main/java/org/karnak/backend/data/entity/ArgumentEntity.java index 9458429e4..837032ff6 100644 --- a/src/main/java/org/karnak/backend/data/entity/ArgumentEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/ArgumentEntity.java @@ -27,11 +27,15 @@ public class ArgumentEntity implements Serializable { private static final long serialVersionUID = -839421871919135822L; private Long id; + private ProfileElementEntity profileElementEntity; + private String key; + private String value; - public ArgumentEntity() {} + public ArgumentEntity() { + } public ArgumentEntity(String key, String value) { this.key = key; diff --git a/src/main/java/org/karnak/backend/data/entity/DestinationEntity.java b/src/main/java/org/karnak/backend/data/entity/DestinationEntity.java index e462ec7bb..0513b6479 100644 --- a/src/main/java/org/karnak/backend/data/entity/DestinationEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/DestinationEntity.java @@ -52,25 +52,41 @@ public class DestinationEntity implements Serializable { private static final long serialVersionUID = 4835879567037810171L; private Long id; + private String description; + private DestinationType destinationType; private boolean activate; + private String condition; + private boolean activateTagMorphing; + private boolean desidentification; + private String issuerByDefault; private PseudonymType pseudonymType; private String tag; + private String delimiter; + private Integer position; + private Boolean savePseudonym; + private boolean filterBySOPClasses; + private Set SOPClassUIDEntityFilters = new HashSet<>(); + private List kheopsAlbumEntities; - private ProjectEntity projectEntity; + + private ProjectEntity deIdentificationProjectEntity; + + private ProjectEntity tagMorphingProjectEntity; + private ForwardNodeEntity forwardNodeEntity; // Activate notification @@ -84,7 +100,8 @@ public class DestinationEntity implements Serializable { // Prefix of the email object when containing an issue. Default value: **ERROR** private String notifyObjectErrorPrefix; - // Pattern of the email object, see https://dzone.com/articles/java-string-format-examples. + // Pattern of the email object, see + // https://dzone.com/articles/java-string-format-examples. // Default value: // [Karnak Notification] %s %.30s private String notifyObjectPattern; @@ -101,12 +118,15 @@ public class DestinationEntity implements Serializable { // the AETitle of the destination node. // mandatory[type=dicom] private String aeTitle; + // the host or IP of the destination node. // mandatory[type=dicom] private String hostname; + // the port of the destination node. // mandatory[type=dicom] private Integer port; + // false by default; if "true" then use the destination AETitle as the calling // AETitle at the gateway side. Otherwise with "false" the calling AETitle is // the AETitle defined in the property "listener.aet" of the file @@ -117,8 +137,10 @@ public class DestinationEntity implements Serializable { // the destination STOW-RS URL. // mandatory[type=stow] private String url; + // credentials of the STOW-RS service (format is "user:password"). private String urlCredentials; + // headers for HTTP request. private String headers; @@ -168,7 +190,7 @@ protected DestinationEntity(DestinationType destinationType) { this.urlCredentials = ""; this.headers = ""; - this.transcodeOnlyUncompressed = true; + this.transcodeOnlyUncompressed = false; } public static DestinationEntity ofDicomEmpty() { @@ -464,16 +486,28 @@ public void setKheopsAlbumEntities(List kheopsAlbumEntities) this.kheopsAlbumEntities = kheopsAlbumEntities; } - @JsonGetter("project") + @JsonGetter("deIdentificationProject") + @ManyToOne + @JoinColumn(name = "deidentification_project_id") + public ProjectEntity getDeIdentificationProjectEntity() { + return deIdentificationProjectEntity; + } + + @JsonSetter("deIdentificationProject") + public void setDeIdentificationProjectEntity(ProjectEntity deIdentificationProjectEntity) { + this.deIdentificationProjectEntity = deIdentificationProjectEntity; + } + + @JsonGetter("tagMorphingProject") @ManyToOne - @JoinColumn(name = "project_id") - public ProjectEntity getProjectEntity() { - return projectEntity; + @JoinColumn(name = "tag_morphing_project_id") + public ProjectEntity getTagMorphingProjectEntity() { + return tagMorphingProjectEntity; } - @JsonSetter("project") - public void setProjectEntity(ProjectEntity projectEntity) { - this.projectEntity = projectEntity; + @JsonSetter("tagMorphingProject") + public void setTagMorphingProjectEntity(ProjectEntity tagMorphingProjectEntity) { + this.tagMorphingProjectEntity = tagMorphingProjectEntity; } public boolean isActivateNotification() { @@ -524,6 +558,14 @@ public void setLastTransfer(LocalDateTime lastTransfer) { this.lastTransfer = lastTransfer; } + public boolean isActivateTagMorphing() { + return activateTagMorphing; + } + + public void setActivateTagMorphing(boolean activateTagMorphing) { + this.activateTagMorphing = activateTagMorphing; + } + /** * Informs if this object matches with the filter as text. * @@ -639,73 +681,73 @@ public String retrieveStringReference() { return "Type of destination is unknown"; } // - // @Override - // public boolean equals(Object o) { - // if (this == o) { - // return true; - // } - // if (o == null || getClass() != o.getClass()) { - // return false; - // } - // DestinationEntity that = (DestinationEntity) o; - // return desidentification == that.desidentification - // && issuerByDefault == that.issuerByDefault - // && filterBySOPClasses == that.filterBySOPClasses - // && Objects.equals(id, that.id) - // && Objects.equals(description, that.description) - // && destinationType == that.destinationType - // && pseudonymType == that.pseudonymType - // && Objects.equals(tag, that.tag) - // && Objects.equals(delimiter, that.delimiter) - // && Objects.equals(position, that.position) - // && Objects.equals(savePseudonym, that.savePseudonym) - // && Objects.equals(transferSyntax, that.transferSyntax) - // && Objects.equals(transcodeOnlyUncompressed, that.transcodeOnlyUncompressed) - // && Objects.equals(activateNotification, that.activateNotification) - // && Objects.equals(notify, that.notify) - // && Objects.equals(notifyObjectErrorPrefix, that.notifyObjectErrorPrefix) - // && Objects.equals(notifyObjectPattern, that.notifyObjectPattern) - // && Objects.equals(notifyObjectValues, that.notifyObjectValues) - // && Objects.equals(notifyInterval, that.notifyInterval) - // && Objects.equals(aeTitle, that.aeTitle) - // && Objects.equals(hostname, that.hostname) - // && Objects.equals(port, that.port) - // && Objects.equals(useaetdest, that.useaetdest) - // && Objects.equals(url, that.url) - // && Objects.equals(urlCredentials, that.urlCredentials) - // && Objects.equals(headers, that.headers); - // } + // @Override + // public boolean equals(Object o) { + // if (this == o) { + // return true; + // } + // if (o == null || getClass() != o.getClass()) { + // return false; + // } + // DestinationEntity that = (DestinationEntity) o; + // return desidentification == that.desidentification + // && issuerByDefault == that.issuerByDefault + // && filterBySOPClasses == that.filterBySOPClasses + // && Objects.equals(id, that.id) + // && Objects.equals(description, that.description) + // && destinationType == that.destinationType + // && pseudonymType == that.pseudonymType + // && Objects.equals(tag, that.tag) + // && Objects.equals(delimiter, that.delimiter) + // && Objects.equals(position, that.position) + // && Objects.equals(savePseudonym, that.savePseudonym) + // && Objects.equals(transferSyntax, that.transferSyntax) + // && Objects.equals(transcodeOnlyUncompressed, that.transcodeOnlyUncompressed) + // && Objects.equals(activateNotification, that.activateNotification) + // && Objects.equals(notify, that.notify) + // && Objects.equals(notifyObjectErrorPrefix, that.notifyObjectErrorPrefix) + // && Objects.equals(notifyObjectPattern, that.notifyObjectPattern) + // && Objects.equals(notifyObjectValues, that.notifyObjectValues) + // && Objects.equals(notifyInterval, that.notifyInterval) + // && Objects.equals(aeTitle, that.aeTitle) + // && Objects.equals(hostname, that.hostname) + // && Objects.equals(port, that.port) + // && Objects.equals(useaetdest, that.useaetdest) + // && Objects.equals(url, that.url) + // && Objects.equals(urlCredentials, that.urlCredentials) + // && Objects.equals(headers, that.headers); + // } // - // @Override - // public int hashCode() { - // return Objects.hash( - // id, - // description, - // destinationType, - // desidentification, - // issuerByDefault, - // pseudonymType, - // tag, - // delimiter, - // position, - // savePseudonym, - // filterBySOPClasses, - // transferSyntax, - // transcodeOnlyUncompressed, - // activateNotification, - // notify, - // notifyObjectErrorPrefix, - // notifyObjectPattern, - // notifyObjectValues, - // notifyInterval, - // aeTitle, - // hostname, - // port, - // useaetdest, - // url, - // urlCredentials, - // headers); - // } + // @Override + // public int hashCode() { + // return Objects.hash( + // id, + // description, + // destinationType, + // desidentification, + // issuerByDefault, + // pseudonymType, + // tag, + // delimiter, + // position, + // savePseudonym, + // filterBySOPClasses, + // transferSyntax, + // transcodeOnlyUncompressed, + // activateNotification, + // notify, + // notifyObjectErrorPrefix, + // notifyObjectPattern, + // notifyObjectValues, + // notifyInterval, + // aeTitle, + // hostname, + // port, + // useaetdest, + // url, + // urlCredentials, + // headers); + // } @Override public boolean equals(Object o) { diff --git a/src/main/java/org/karnak/backend/data/entity/DicomSourceNodeEntity.java b/src/main/java/org/karnak/backend/data/entity/DicomSourceNodeEntity.java index 333af93c1..09d862a53 100644 --- a/src/main/java/org/karnak/backend/data/entity/DicomSourceNodeEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/DicomSourceNodeEntity.java @@ -28,15 +28,20 @@ public class DicomSourceNodeEntity implements Serializable { private static final long serialVersionUID = -4917273057619947934L; private Long id; + private String description; + // AETitle of the source node. private String aeTitle; + // the host or IP of the source node. If the hostname exists then it is checked // (allows a restriction on the host not only in the AETitle). private String hostname; + // if "true" check the hostname during the DICOM association and if not match // the connection is abort private Boolean checkHostname; + private ForwardNodeEntity forwardNodeEntity; public DicomSourceNodeEntity() { diff --git a/src/main/java/org/karnak/backend/data/entity/ExcludedTagEntity.java b/src/main/java/org/karnak/backend/data/entity/ExcludedTagEntity.java index e96da45cc..ab7fe7bd9 100644 --- a/src/main/java/org/karnak/backend/data/entity/ExcludedTagEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/ExcludedTagEntity.java @@ -19,7 +19,8 @@ public class ExcludedTagEntity extends TagEntity implements Serializable { private static final long serialVersionUID = -5068272710332856139L; - public ExcludedTagEntity() {} + public ExcludedTagEntity() { + } public ExcludedTagEntity(String tagValue, ProfileElementEntity profileElementEntity) { super(tagValue, profileElementEntity); diff --git a/src/main/java/org/karnak/backend/data/entity/ForwardNodeEntity.java b/src/main/java/org/karnak/backend/data/entity/ForwardNodeEntity.java index 516e03225..639c03c1f 100644 --- a/src/main/java/org/karnak/backend/data/entity/ForwardNodeEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/ForwardNodeEntity.java @@ -31,14 +31,18 @@ public class ForwardNodeEntity implements Serializable { private static final long serialVersionUID = 2095439136652046994L; private Long id; + private String fwdDescription; + // AETitle which defined a mapping of the gateway. This AETitle is configured as // a destination in the DICOM component that sends images to the gateway. private String fwdAeTitle; + // Specification of a DICOM source node (the one which sends images to the // gateway). When no source node is defined all the DICOM nodes are accepted by // the gateway. private Set sourceNodes = new HashSet<>(); + // Specification of a final DICOM destination node. Multiple destinations can be // defined either as a DICOM or DICOMWeb type. private Set destinationEntities = new HashSet<>(); diff --git a/src/main/java/org/karnak/backend/data/entity/IncludedTagEntity.java b/src/main/java/org/karnak/backend/data/entity/IncludedTagEntity.java index 845097709..a48498e78 100644 --- a/src/main/java/org/karnak/backend/data/entity/IncludedTagEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/IncludedTagEntity.java @@ -19,7 +19,8 @@ public class IncludedTagEntity extends TagEntity implements Serializable { private static final long serialVersionUID = 6644786515302502293L; - public IncludedTagEntity() {} + public IncludedTagEntity() { + } public IncludedTagEntity(String tagValue, ProfileElementEntity profileElementEntity) { super(tagValue, profileElementEntity); diff --git a/src/main/java/org/karnak/backend/data/entity/KheopsAlbumsEntity.java b/src/main/java/org/karnak/backend/data/entity/KheopsAlbumsEntity.java index fbefaade7..9470e337a 100644 --- a/src/main/java/org/karnak/backend/data/entity/KheopsAlbumsEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/KheopsAlbumsEntity.java @@ -26,13 +26,19 @@ public class KheopsAlbumsEntity implements Serializable { private static final long serialVersionUID = -3315720301354286325L; private Long id; + private String urlAPI; + private String authorizationDestination; + private String authorizationSource; + private String condition; + private DestinationEntity destinationEntity = new DestinationEntity(); - public KheopsAlbumsEntity() {} + public KheopsAlbumsEntity() { + } public KheopsAlbumsEntity( String urlAPI, diff --git a/src/main/java/org/karnak/backend/data/entity/MaskEntity.java b/src/main/java/org/karnak/backend/data/entity/MaskEntity.java index acbebea11..5dd1e0dfe 100644 --- a/src/main/java/org/karnak/backend/data/entity/MaskEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/MaskEntity.java @@ -34,12 +34,17 @@ public class MaskEntity implements Serializable { private static final long serialVersionUID = 1833858684629178458L; private Long id; + private ProfileEntity profileEntity; + private String stationName; + private String color; + private List rectangles = new ArrayList<>(); - public MaskEntity() {} + public MaskEntity() { + } public MaskEntity(String stationName, String color, ProfileEntity profileEntity) { this.stationName = stationName; diff --git a/src/main/java/org/karnak/backend/data/entity/ProfileElementEntity.java b/src/main/java/org/karnak/backend/data/entity/ProfileElementEntity.java index e6bbc916c..6e77926f9 100644 --- a/src/main/java/org/karnak/backend/data/entity/ProfileElementEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/ProfileElementEntity.java @@ -41,18 +41,29 @@ public class ProfileElementEntity implements Serializable { private static final long serialVersionUID = 818925943276758147L; private Long id; + private String name; + private String codename; + private String condition; + private String action; + private String option; + private Integer position; + private ProfileEntity profileEntity; + private List includedTagEntities = new ArrayList<>(); + private List excludedTagEntities = new ArrayList<>(); + private List argumentEntities = new ArrayList<>(); - public ProfileElementEntity() {} + public ProfileElementEntity() { + } public ProfileElementEntity( String name, diff --git a/src/main/java/org/karnak/backend/data/entity/ProfileEntity.java b/src/main/java/org/karnak/backend/data/entity/ProfileEntity.java index 45b0073bf..63da0045d 100644 --- a/src/main/java/org/karnak/backend/data/entity/ProfileEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/ProfileEntity.java @@ -36,28 +36,38 @@ @Table(name = "profile") @JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonPropertyOrder({ - "name", - "version", - "minimumKarnakVersion", - "defaultIssuerOfPatientID", - "profileElementEntities", - "maskEntities" + "name", + "version", + "minimumKarnakVersion", + "defaultIssuerOfPatientID", + "profileElementEntities", + "maskEntities" }) public class ProfileEntity implements Serializable { private static final long serialVersionUID = -7178858361090900170L; private Long id; + private String name; + private String version; + private String minimumKarnakVersion; - private String defaultIssuerOfPatientId; // not use in db but used in warning msg profile + + private String defaultIssuerOfPatientId; // not use in db but used in warning msg + // profile + private Boolean byDefault; + private Set profileElementEntities = new HashSet<>(); + private Set maskEntities = new HashSet<>(); + private List projectEntities; - public ProfileEntity() {} + public ProfileEntity() { + } public ProfileEntity( String name, String version, String minimumKarnakVersion, String defaultIssuerOfPatientId) { diff --git a/src/main/java/org/karnak/backend/data/entity/ProjectEntity.java b/src/main/java/org/karnak/backend/data/entity/ProjectEntity.java index 3817f1b86..94d9dc152 100644 --- a/src/main/java/org/karnak/backend/data/entity/ProjectEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/ProjectEntity.java @@ -34,9 +34,13 @@ public class ProjectEntity implements Serializable { private static final long serialVersionUID = 8809562914582842501L; private Long id; + private String name; + private List secretEntities; + private List destinationEntities; + private ProfileEntity profileEntity; public ProjectEntity() { @@ -72,7 +76,7 @@ public void setSecretEntities(List secretEntities) { this.secretEntities = secretEntities; } - @OneToMany(mappedBy = "projectEntity") + @OneToMany(mappedBy = "deIdentificationProjectEntity") @LazyCollection(LazyCollectionOption.FALSE) public List getDestinationEntities() { return destinationEntities; diff --git a/src/main/java/org/karnak/backend/data/entity/SOPClassUIDEntity.java b/src/main/java/org/karnak/backend/data/entity/SOPClassUIDEntity.java index 8b3c99584..f493099e6 100644 --- a/src/main/java/org/karnak/backend/data/entity/SOPClassUIDEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/SOPClassUIDEntity.java @@ -24,11 +24,15 @@ public class SOPClassUIDEntity implements Serializable { private static final long serialVersionUID = 2885426916053925842L; private Long id; + private String ciod; + private String uid; + private String name; - public SOPClassUIDEntity() {} + public SOPClassUIDEntity() { + } public SOPClassUIDEntity(String ciod, String uid, String name) { this.ciod = ciod; diff --git a/src/main/java/org/karnak/backend/data/entity/SecretEntity.java b/src/main/java/org/karnak/backend/data/entity/SecretEntity.java index d21127641..79be59abd 100644 --- a/src/main/java/org/karnak/backend/data/entity/SecretEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/SecretEntity.java @@ -26,12 +26,17 @@ public class SecretEntity implements Serializable { private Long id; + private ProjectEntity projectEntity; + private byte[] key; + private LocalDateTime creationDate; + private boolean active; - public SecretEntity() {} + public SecretEntity() { + } public SecretEntity(byte[] key) { this.key = key; diff --git a/src/main/java/org/karnak/backend/data/entity/TagEntity.java b/src/main/java/org/karnak/backend/data/entity/TagEntity.java index 55263e937..1b6b7cd4a 100644 --- a/src/main/java/org/karnak/backend/data/entity/TagEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/TagEntity.java @@ -35,10 +35,13 @@ public abstract class TagEntity implements Serializable { private static final long serialVersionUID = -1172918773653197764L; private Long id; + private ProfileElementEntity profileElementEntity; + private String tagValue; - public TagEntity() {} + public TagEntity() { + } public TagEntity(String tagValue, ProfileElementEntity profileElementEntity) { this.tagValue = tagValue; diff --git a/src/main/java/org/karnak/backend/data/entity/TransferStatusEntity.java b/src/main/java/org/karnak/backend/data/entity/TransferStatusEntity.java index 52146aa8b..1dc5034cf 100644 --- a/src/main/java/org/karnak/backend/data/entity/TransferStatusEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/TransferStatusEntity.java @@ -37,50 +37,68 @@ public class TransferStatusEntity implements Serializable { private static final long serialVersionUID = -1542928573652195764L; private Long id; - @CsvRecurse private ForwardNodeEntity forwardNodeEntity; + + @CsvRecurse + private ForwardNodeEntity forwardNodeEntity; + private Long forwardNodeId; - @CsvRecurse private DestinationEntity destinationEntity; + + @CsvRecurse + private DestinationEntity destinationEntity; + private Long destinationId; @CsvDate(DateFormat.FORMAT_DDMMYYYY_SLASH_HHMMSS_2POINTS_SSSSSS_POINT) private LocalDateTime transferDate; private boolean sent; + private String reason; + // Original private String patientIdOriginal; + private String accessionNumberOriginal; + private String studyDescriptionOriginal; @CsvDate(DateFormat.FORMAT_DDMMYYYY_SLASH_HHMMSS_2POINTS_SSSSSS_POINT) private LocalDateTime studyDateOriginal; private String studyUidOriginal; + private String serieDescriptionOriginal; @CsvDate(DateFormat.FORMAT_DDMMYYYY_SLASH_HHMMSS_2POINTS_SSSSSS_POINT) private LocalDateTime serieDateOriginal; private String serieUidOriginal; + private String sopInstanceUidOriginal; + // To send private String patientIdToSend; + private String accessionNumberToSend; + private String studyDescriptionToSend; @CsvDate(DateFormat.FORMAT_DDMMYYYY_SLASH_HHMMSS_2POINTS_SSSSSS_POINT) private LocalDateTime studyDateToSend; private String studyUidToSend; + private String serieDescriptionToSend; @CsvDate(DateFormat.FORMAT_DDMMYYYY_SLASH_HHMMSS_2POINTS_SSSSSS_POINT) private LocalDateTime serieDateToSend; private String serieUidToSend; + private String sopInstanceUidToSend; - public TransferStatusEntity() {} + public TransferStatusEntity() { + } public TransferStatusEntity( Long forwardNodeId, diff --git a/src/main/java/org/karnak/backend/data/entity/VersionEntity.java b/src/main/java/org/karnak/backend/data/entity/VersionEntity.java index 4586c0efa..9b8442eff 100644 --- a/src/main/java/org/karnak/backend/data/entity/VersionEntity.java +++ b/src/main/java/org/karnak/backend/data/entity/VersionEntity.java @@ -22,6 +22,7 @@ public class VersionEntity implements Serializable { private Long id; + private long gatewaySetup; @Id diff --git a/src/main/java/org/karnak/backend/data/repo/ArgumentRepo.java b/src/main/java/org/karnak/backend/data/repo/ArgumentRepo.java index acdf1ea14..d267f951f 100644 --- a/src/main/java/org/karnak/backend/data/repo/ArgumentRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/ArgumentRepo.java @@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface ArgumentRepo extends JpaRepository {} +public interface ArgumentRepo extends JpaRepository { + +} diff --git a/src/main/java/org/karnak/backend/data/repo/DestinationRepo.java b/src/main/java/org/karnak/backend/data/repo/DestinationRepo.java index b981f6dfc..deaf25dc0 100644 --- a/src/main/java/org/karnak/backend/data/repo/DestinationRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/DestinationRepo.java @@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface DestinationRepo extends JpaRepository {} +public interface DestinationRepo extends JpaRepository { + +} diff --git a/src/main/java/org/karnak/backend/data/repo/DicomSourceNodeRepo.java b/src/main/java/org/karnak/backend/data/repo/DicomSourceNodeRepo.java index 432f5671e..556ae8a14 100644 --- a/src/main/java/org/karnak/backend/data/repo/DicomSourceNodeRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/DicomSourceNodeRepo.java @@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface DicomSourceNodeRepo extends JpaRepository {} +public interface DicomSourceNodeRepo extends JpaRepository { + +} diff --git a/src/main/java/org/karnak/backend/data/repo/ForwardNodeRepo.java b/src/main/java/org/karnak/backend/data/repo/ForwardNodeRepo.java index 239fbea20..f16a9617e 100644 --- a/src/main/java/org/karnak/backend/data/repo/ForwardNodeRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/ForwardNodeRepo.java @@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface ForwardNodeRepo extends JpaRepository {} +public interface ForwardNodeRepo extends JpaRepository { + +} diff --git a/src/main/java/org/karnak/backend/data/repo/MaskRepo.java b/src/main/java/org/karnak/backend/data/repo/MaskRepo.java index 46bde1017..66ca3943d 100644 --- a/src/main/java/org/karnak/backend/data/repo/MaskRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/MaskRepo.java @@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface MaskRepo extends JpaRepository {} +public interface MaskRepo extends JpaRepository { + +} diff --git a/src/main/java/org/karnak/backend/data/repo/ProfileElementRepo.java b/src/main/java/org/karnak/backend/data/repo/ProfileElementRepo.java index 62837db5d..4b441c808 100644 --- a/src/main/java/org/karnak/backend/data/repo/ProfileElementRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/ProfileElementRepo.java @@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface ProfileElementRepo extends JpaRepository {} +public interface ProfileElementRepo extends JpaRepository { + +} diff --git a/src/main/java/org/karnak/backend/data/repo/ProjectRepo.java b/src/main/java/org/karnak/backend/data/repo/ProjectRepo.java index 192ba9e45..c80ac66dd 100644 --- a/src/main/java/org/karnak/backend/data/repo/ProjectRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/ProjectRepo.java @@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface ProjectRepo extends JpaRepository {} +public interface ProjectRepo extends JpaRepository { + +} diff --git a/src/main/java/org/karnak/backend/data/repo/SecretRepo.java b/src/main/java/org/karnak/backend/data/repo/SecretRepo.java index c4ebefbcc..8fe5c4289 100644 --- a/src/main/java/org/karnak/backend/data/repo/SecretRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/SecretRepo.java @@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface SecretRepo extends JpaRepository {} +public interface SecretRepo extends JpaRepository { + +} diff --git a/src/main/java/org/karnak/backend/data/repo/TagRepo.java b/src/main/java/org/karnak/backend/data/repo/TagRepo.java index cf964b068..24962e88f 100644 --- a/src/main/java/org/karnak/backend/data/repo/TagRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/TagRepo.java @@ -14,4 +14,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface TagRepo extends JpaRepository {} +public interface TagRepo extends JpaRepository { + +} diff --git a/src/main/java/org/karnak/backend/data/repo/TransferStatusRepo.java b/src/main/java/org/karnak/backend/data/repo/TransferStatusRepo.java index 0c777ef8e..4a0e00463 100644 --- a/src/main/java/org/karnak/backend/data/repo/TransferStatusRepo.java +++ b/src/main/java/org/karnak/backend/data/repo/TransferStatusRepo.java @@ -21,7 +21,7 @@ @Repository public interface TransferStatusRepo extends JpaRepository, - JpaSpecificationExecutor { + JpaSpecificationExecutor { /** * Look for TransferStatusEntity for a destination @@ -35,7 +35,7 @@ public interface TransferStatusRepo * Look for TransferStatusEntity for a destination and after the last check date * * @param destinationId Destination id - * @param lastCheck Date of the last check + * @param lastCheck Date of the last check * @return TransferStatusEntity found */ List findByDestinationIdAndTransferDateAfter( diff --git a/src/main/java/org/karnak/backend/data/repo/specification/TransferStatusSpecification.java b/src/main/java/org/karnak/backend/data/repo/specification/TransferStatusSpecification.java index 9df94a702..bd877a7b6 100644 --- a/src/main/java/org/karnak/backend/data/repo/specification/TransferStatusSpecification.java +++ b/src/main/java/org/karnak/backend/data/repo/specification/TransferStatusSpecification.java @@ -25,10 +25,13 @@ import org.karnak.frontend.monitoring.component.TransferStatusFilter; import org.springframework.data.jpa.domain.Specification; -/** Transfer status specification: used to look for entries depending on criteria */ +/** + * Transfer status specification: used to look for entries depending on criteria + */ public class TransferStatusSpecification implements Specification { - @Serial private static final long serialVersionUID = -939448741462690254L; + @Serial + private static final long serialVersionUID = -939448741462690254L; // Like character private static final String LIKE = "%"; @@ -81,16 +84,16 @@ public Predicate toPredicate( buildCriteriaTransferDate(criteriaBuilder, predicates, pTransferDate); } - return criteriaBuilder.and(predicates.toArray(new Predicate[] {})); + return criteriaBuilder.and(predicates.toArray(new Predicate[]{})); } /** * Build criteria for study uid * - * @param criteriaBuilder CriteriaBuilder - * @param predicates Predicates to build + * @param criteriaBuilder CriteriaBuilder + * @param predicates Predicates to build * @param pStudyUidOriginal Path of study uid original - * @param pStudyUidToSend Path of study uid to send + * @param pStudyUidToSend Path of study uid to send */ private void buildCriteriaStudyUid( CriteriaBuilder criteriaBuilder, @@ -111,10 +114,10 @@ private void buildCriteriaStudyUid( /** * Build criteria for serie uid * - * @param criteriaBuilder CriteriaBuilder - * @param predicates Predicates to build + * @param criteriaBuilder CriteriaBuilder + * @param predicates Predicates to build * @param pSerieUidOriginal Path of serie uid original - * @param pSerieUidToSend Path of serie uid to send + * @param pSerieUidToSend Path of serie uid to send */ private void buildCriteriaSerieUid( CriteriaBuilder criteriaBuilder, @@ -135,10 +138,10 @@ private void buildCriteriaSerieUid( /** * Build criteria for sop instance uid * - * @param criteriaBuilder CriteriaBuilder - * @param predicates Predicates to build + * @param criteriaBuilder CriteriaBuilder + * @param predicates Predicates to build * @param pSopInstanceUidOriginal Path of sop instance uid original - * @param pSopInstanceUidToSend Path of sop instance uid to send + * @param pSopInstanceUidToSend Path of sop instance uid to send */ private void buildCriteriaSopInstanceUid( CriteriaBuilder criteriaBuilder, @@ -160,8 +163,8 @@ private void buildCriteriaSopInstanceUid( * Build criteria for sent * * @param criteriaBuilder CriteriaBuilder - * @param predicates Predicates to build - * @param pSent Path of sent + * @param predicates Predicates to build + * @param pSent Path of sent */ private void buildCriteriaSent( CriteriaBuilder criteriaBuilder, List predicates, Path pSent) { @@ -176,8 +179,8 @@ private void buildCriteriaSent( * Build criteria for transfer date * * @param criteriaBuilder CriteriaBuilder - * @param predicates Predicates to build - * @param pTransferDate Path of transfer date + * @param predicates Predicates to build + * @param pTransferDate Path of transfer date */ private void buildCriteriaTransferDate( CriteriaBuilder criteriaBuilder, diff --git a/src/main/java/org/karnak/backend/data/validator/DestinationGroupSequenceProvider.java b/src/main/java/org/karnak/backend/data/validator/DestinationGroupSequenceProvider.java index 9bbd6a973..974ea875f 100644 --- a/src/main/java/org/karnak/backend/data/validator/DestinationGroupSequenceProvider.java +++ b/src/main/java/org/karnak/backend/data/validator/DestinationGroupSequenceProvider.java @@ -17,8 +17,7 @@ import org.karnak.backend.enums.DestinationType; /** - * @see - * https://stackoverflow.com/questions/27173960/jsr303-apply-all-validation-groups-defined-in-sequence + * @see https://stackoverflow.com/questions/27173960/jsr303-apply-all-validation-groups-defined-in-sequence */ public class DestinationGroupSequenceProvider implements DefaultGroupSequenceProvider { @@ -40,14 +39,20 @@ public List> getValidationGroups(DestinationEntity destinationEntity) { return DEFAULT_GROUPS; } - public interface DestinationDicomGroup {} + public interface DestinationDicomGroup { + + } private static final List> DEFAULT_GROUPS = // Collections.singletonList(DestinationEntity.class); + private static final List> TYPE_DICOM_GROUPS = // Arrays.asList(DestinationEntity.class, DestinationDicomGroup.class); + private static final List> TYPE_STOW_GROUPS = // Arrays.asList(DestinationEntity.class, DestinationStowGroup.class); - public interface DestinationStowGroup {} + public interface DestinationStowGroup { + + } } diff --git a/src/main/java/org/karnak/backend/dicom/DateTimeUtils.java b/src/main/java/org/karnak/backend/dicom/DateTimeUtils.java index 082c8f1cc..0fd4b60d0 100644 --- a/src/main/java/org/karnak/backend/dicom/DateTimeUtils.java +++ b/src/main/java/org/karnak/backend/dicom/DateTimeUtils.java @@ -9,10 +9,22 @@ */ package org.karnak.backend.dicom; -import static java.time.temporal.ChronoField.*; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.NANO_OF_SECOND; - -import java.time.*; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import static java.time.temporal.ChronoField.YEAR; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.FormatStyle; @@ -29,6 +41,7 @@ * @since Apr 2019 */ public class DateTimeUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(DateTimeUtils.class); private static final DateTimeFormatter DA_PARSER = @@ -173,13 +186,17 @@ public static String formatDT(Temporal value) { } public static String truncateTM(String value, int maxLength) { - if (maxLength < 2) throw new IllegalArgumentException("maxLength %d < 2" + maxLength); + if (maxLength < 2) { + throw new IllegalArgumentException("maxLength %d < 2" + maxLength); + } return truncate(value, value.length(), maxLength, 8); } public static String truncateDT(String value, int maxLength) { - if (maxLength < 4) throw new IllegalArgumentException("maxLength %d < 4" + maxLength); + if (maxLength < 4) { + throw new IllegalArgumentException("maxLength %d < 4" + maxLength); + } int index = indexOfZone(value); return index < 0 @@ -192,7 +209,9 @@ private static long nanosToAdd(String tm) { int index = tm.lastIndexOf(':'); if (index > 0) { length--; - if (index > 4) length--; + if (index > 4) { + length--; + } } return nanosToAdd(length); } @@ -266,6 +285,7 @@ private static int adjustMaxLength(int maxLength, int fractionPos) { private static final DateTimeFormatter defaultTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM); + private static final DateTimeFormatter defaultDateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM); diff --git a/src/main/java/org/karnak/backend/dicom/Defacer.java b/src/main/java/org/karnak/backend/dicom/Defacer.java index 88aaa9be2..c98600c65 100644 --- a/src/main/java/org/karnak/backend/dicom/Defacer.java +++ b/src/main/java/org/karnak/backend/dicom/Defacer.java @@ -28,7 +28,8 @@ public class Defacer { public static final String APPLY_DEFACING = "defacing"; - private Defacer() {} + private Defacer() { + } public static PlanarImage apply(Attributes attributes, PlanarImage image) { PlanarImage faceDetectionImg = faceDetection(attributes, image); @@ -114,7 +115,8 @@ public static PlanarImage addRandPxlLine( int maxThicknessSkin = (int) (3 / pixelSpacing); // 3mm // DRAW A LINE WITH RANDOM VALUE WHEN FACE DETECTED int yOffsetRand = 1; - // scan the image from left to right and bottom to top until the face is detected in Y + // scan the image from left to right and bottom to top until the face is detected + // in Y for (int x = 0; x < faceDetectImg.width(); x++) { boolean faceDetected = false; int yFaceDetected = 0; diff --git a/src/main/java/org/karnak/backend/dicom/DefacingUtil.java b/src/main/java/org/karnak/backend/dicom/DefacingUtil.java index 495b8f14a..7bab9ad8c 100644 --- a/src/main/java/org/karnak/backend/dicom/DefacingUtil.java +++ b/src/main/java/org/karnak/backend/dicom/DefacingUtil.java @@ -19,7 +19,8 @@ public class DefacingUtil { - private DefacingUtil() {} + private DefacingUtil() { + } public static int randomY(int minY, int maxY, int bound) { SecureRandom random = new SecureRandom(); diff --git a/src/main/java/org/karnak/backend/dicom/DicomForwardDestination.java b/src/main/java/org/karnak/backend/dicom/DicomForwardDestination.java index fb89e6056..2a84c5b35 100644 --- a/src/main/java/org/karnak/backend/dicom/DicomForwardDestination.java +++ b/src/main/java/org/karnak/backend/dicom/DicomForwardDestination.java @@ -22,10 +22,13 @@ public class DicomForwardDestination extends ForwardDestination { private final StoreFromStreamSCU streamSCU; + private final DeviceOpService streamSCUService; + private final boolean useDestinationAetForKeyMap; private final ForwardDicomNode callingNode; + private final DicomNode destinationNode; public DicomForwardDestination(ForwardDicomNode fwdNode, DicomNode destinationNode) @@ -49,9 +52,10 @@ public DicomForwardDestination( } /** - * @param forwardParams optional advanced parameters (proxy, authentication, connection and TLS) - * @param fwdNode the DICOM forwarding node. Cannot be null. - * @param destinationNode the DICOM destination node. Cannot be null. + * @param forwardParams optional advanced parameters (proxy, authentication, + * connection and TLS) + * @param fwdNode the DICOM forwarding node. Cannot be null. + * @param destinationNode the DICOM destination node. Cannot be null. * @param useDestinationAetForKeyMap * @param progress * @param editors @@ -121,10 +125,10 @@ public DicomNode getDestinationNode() { @Override public void stop() { - // Association as = streamSCU.getAssociation(); - // if (as != null && as.isReadyForDataTransfer()) { - // as.abort(); - // } + // Association as = streamSCU.getAssociation(); + // if (as != null && as.isReadyForDataTransfer()) { + // as.abort(); + // } streamSCU.close(true); streamSCUService.stop(); } diff --git a/src/main/java/org/karnak/backend/dicom/ForwardDestination.java b/src/main/java/org/karnak/backend/dicom/ForwardDestination.java index 1c734419b..342b648a6 100644 --- a/src/main/java/org/karnak/backend/dicom/ForwardDestination.java +++ b/src/main/java/org/karnak/backend/dicom/ForwardDestination.java @@ -20,8 +20,11 @@ public abstract class ForwardDestination { protected final List dicomEditors; + private final Long id; + private boolean transcodeOnlyUncompressed = true; + private String outputTransferSyntax = ""; protected ForwardDestination(Long id, List dicomEditors) { diff --git a/src/main/java/org/karnak/backend/dicom/ForwardDicomNode.java b/src/main/java/org/karnak/backend/dicom/ForwardDicomNode.java index 9845a21ff..f38e66e23 100644 --- a/src/main/java/org/karnak/backend/dicom/ForwardDicomNode.java +++ b/src/main/java/org/karnak/backend/dicom/ForwardDicomNode.java @@ -16,7 +16,9 @@ public class ForwardDicomNode extends DicomNode { private final String forwardAETitle; + private final Set acceptedSourceNodes; + private final Long id; public ForwardDicomNode(DicomNode dicomNode) { @@ -78,11 +80,15 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (this == obj) return true; + if (this == obj) { + return true; + } if (obj == null) { return false; } - if (getClass() != obj.getClass()) return false; + if (getClass() != obj.getClass()) { + return false; + } ForwardDicomNode other = (ForwardDicomNode) obj; return forwardAETitle.equals(other.forwardAETitle); } diff --git a/src/main/java/org/karnak/backend/dicom/ImageOrientation.java b/src/main/java/org/karnak/backend/dicom/ImageOrientation.java index aba17de45..f3b14cd88 100644 --- a/src/main/java/org/karnak/backend/dicom/ImageOrientation.java +++ b/src/main/java/org/karnak/backend/dicom/ImageOrientation.java @@ -27,7 +27,8 @@ * be designated by one or two additional letters in each value. Within each value, the letters * shall be ordered with the principal orientation designated in the first character. * - *

C.7.6.2.1.1 Image Position And Image Orientation. The Image Position (0020,0032) specifies the + *

C.7.6.2.1.1 Image Position And Image Orientation. The Image Position (0020,0032) specifies + * the * x, y, and z coordinates of the upper left hand corner of the image; it is the center of the first * voxel transmitted. Image Orientation (0020,0037) specifies the direction cosines of the first row * and the first column with respect to the patient. These Attributes shall be provide as a pair. @@ -53,10 +54,15 @@ public enum Label { } public static final String DIR_R = "R"; // NON-NLS + public static final String DIR_L = "L"; // NON-NLS + public static final String DIR_A = "A"; // NON-NLS + public static final String DIR_P = "P"; // NON-NLS + public static final String DIR_F = "F"; // NON-NLS + public static final String DIR_H = "H"; // NON-NLS private static final double OBLIQUITY_THRESHOLD = 0.8; @@ -65,7 +71,8 @@ public enum Label { * Get a label describing the major axis from a unit vector (direction cosine) as found in * ImageOrientationPatient. * - *

Some degree of deviation from one of the standard orthogonal axes is allowed before deciding + *

Some degree of deviation from one of the standard orthogonal axes is allowed before + * deciding * no major axis applies and returning null. * * @param x diff --git a/src/main/java/org/karnak/backend/dicom/Params.java b/src/main/java/org/karnak/backend/dicom/Params.java index 460c40480..9980d6ab2 100644 --- a/src/main/java/org/karnak/backend/dicom/Params.java +++ b/src/main/java/org/karnak/backend/dicom/Params.java @@ -15,10 +15,15 @@ public final class Params { private final String iuid; + private final String cuid; + private final String tsuid; + private final InputStream data; + private final Association as; + private final int priority; public Params( diff --git a/src/main/java/org/karnak/backend/dicom/WebForwardDestination.java b/src/main/java/org/karnak/backend/dicom/WebForwardDestination.java index 26c24e4f1..519025210 100644 --- a/src/main/java/org/karnak/backend/dicom/WebForwardDestination.java +++ b/src/main/java/org/karnak/backend/dicom/WebForwardDestination.java @@ -22,7 +22,9 @@ public class WebForwardDestination extends ForwardDestination { private final ForwardDicomNode callingNode; + private final DicomState state; + private final DicomStowRS stowRS; public WebForwardDestination(ForwardDicomNode fwdNode, String requestURL) { diff --git a/src/main/java/org/karnak/backend/enums/ApplicationProfile.java b/src/main/java/org/karnak/backend/enums/ApplicationProfile.java index 020f61294..adbf7a701 100644 --- a/src/main/java/org/karnak/backend/enums/ApplicationProfile.java +++ b/src/main/java/org/karnak/backend/enums/ApplicationProfile.java @@ -9,13 +9,19 @@ */ package org.karnak.backend.enums; -/** Application profile */ +/** + * Application profile + */ public enum ApplicationProfile { - /** Profile OIDC: use to activate the application profile: application-oidc.yml */ + /** + * Profile OIDC: use to activate the application profile: application-oidc.yml + */ OIDC("oidc"); - /** Name of the profile to activate */ + /** + * Name of the profile to activate + */ final String code; ApplicationProfile(final String code) { diff --git a/src/main/java/org/karnak/backend/enums/EnvironmentVariable.java b/src/main/java/org/karnak/backend/enums/EnvironmentVariable.java index 0e62e4036..07b24ebaf 100644 --- a/src/main/java/org/karnak/backend/enums/EnvironmentVariable.java +++ b/src/main/java/org/karnak/backend/enums/EnvironmentVariable.java @@ -9,7 +9,9 @@ */ package org.karnak.backend.enums; -/** Environment variables of the system */ +/** + * Environment variables of the system + */ public enum EnvironmentVariable { /** @@ -18,7 +20,9 @@ public enum EnvironmentVariable { */ IDP("IDP"); - /** Name of the environment variable */ + /** + * Name of the environment variable + */ final String code; EnvironmentVariable(final String code) { diff --git a/src/main/java/org/karnak/backend/enums/MessageType.java b/src/main/java/org/karnak/backend/enums/MessageType.java index 4196b78c0..197767aee 100644 --- a/src/main/java/org/karnak/backend/enums/MessageType.java +++ b/src/main/java/org/karnak/backend/enums/MessageType.java @@ -11,5 +11,7 @@ public enum MessageType { NOTIFICATION_MESSAGE, // The message is displayed in a Notification - STATIC_MESSAGE // The message is displayed inside the current component (Dialog, Layout, ...) + STATIC_MESSAGE // The message is displayed inside the current component (Dialog, + // Layout, ...) + } diff --git a/src/main/java/org/karnak/backend/enums/ProfileItemType.java b/src/main/java/org/karnak/backend/enums/ProfileItemType.java index c3bb12152..079f5fe94 100644 --- a/src/main/java/org/karnak/backend/enums/ProfileItemType.java +++ b/src/main/java/org/karnak/backend/enums/ProfileItemType.java @@ -43,8 +43,11 @@ public enum ProfileItemType { EXPRESSION_TAGS(Expression.class, "expression.on.tags", null, null); private final Class profileClass; + private final String classAlias; + private final String codeValue; + private final String codeMeaning; ProfileItemType( diff --git a/src/main/java/org/karnak/backend/enums/SecurityRole.java b/src/main/java/org/karnak/backend/enums/SecurityRole.java index 34fed8200..837544478 100644 --- a/src/main/java/org/karnak/backend/enums/SecurityRole.java +++ b/src/main/java/org/karnak/backend/enums/SecurityRole.java @@ -20,10 +20,14 @@ public enum SecurityRole { // Role user USER_ROLE("ROLE_user", "user"); - /** Role of the enum */ + /** + * Role of the enum + */ private final String role; - /** Type of the enum */ + /** + * Type of the enum + */ private final String type; /** diff --git a/src/main/java/org/karnak/backend/enums/TransferStatusType.java b/src/main/java/org/karnak/backend/enums/TransferStatusType.java index ede4bb260..6a23addf1 100644 --- a/src/main/java/org/karnak/backend/enums/TransferStatusType.java +++ b/src/main/java/org/karnak/backend/enums/TransferStatusType.java @@ -9,22 +9,28 @@ */ package org.karnak.backend.enums; -/** Enum for the transfer status */ +/** + * Enum for the transfer status + */ public enum TransferStatusType { ALL(null, "All"), SENT(true, "Sent"), NOT_SENT(false, "Not Sent"); - /** Code of the enum */ + /** + * Code of the enum + */ private final Boolean code; - /** Description of the enum */ + /** + * Description of the enum + */ private final String description; /** * Constructor * - * @param code Code + * @param code Code * @param description Description */ TransferStatusType(Boolean code, String description) { diff --git a/src/main/java/org/karnak/backend/enums/UIDType.java b/src/main/java/org/karnak/backend/enums/UIDType.java index 2992e7a8e..7e65520a5 100644 --- a/src/main/java/org/karnak/backend/enums/UIDType.java +++ b/src/main/java/org/karnak/backend/enums/UIDType.java @@ -38,19 +38,25 @@ public enum UIDType { JPEG_2000_LOSSLESS("1.2.840.10008.1.2.4.90", "JPEG 2000 Image Compression (Lossless Only)"), JPEG_2000("1.2.840.10008.1.2.4.91", "JPEG 2000 Image Compression"); - /** Code of the enum */ + /** + * Code of the enum + */ private final String code; - /** Description of the enum */ + /** + * Description of the enum + */ private final String description; - /** Default description */ + /** + * Default description + */ public static final String DEFAULT_DESCRIPTION = "Keep original transfer syntax"; /** * Constructor * - * @param code Code + * @param code Code * @param description Description */ UIDType(String code, String description) { diff --git a/src/main/java/org/karnak/backend/exception/AbortException.java b/src/main/java/org/karnak/backend/exception/AbortException.java index e3c086f73..467e78912 100644 --- a/src/main/java/org/karnak/backend/exception/AbortException.java +++ b/src/main/java/org/karnak/backend/exception/AbortException.java @@ -14,6 +14,7 @@ public final class AbortException extends IllegalStateException { private static final long serialVersionUID = 3993065212756372490L; + private final Abort abort; public AbortException(Abort abort, String s) { diff --git a/src/main/java/org/karnak/backend/model/FileInfo.java b/src/main/java/org/karnak/backend/model/FileInfo.java index 86505e0e1..6f1d1d348 100644 --- a/src/main/java/org/karnak/backend/model/FileInfo.java +++ b/src/main/java/org/karnak/backend/model/FileInfo.java @@ -12,8 +12,11 @@ public final class FileInfo { private final String iuid; + private final String cuid; + private final String tsuid; + private final String filename; public FileInfo(String filename, String iuid, String cuid, String tsuid) { diff --git a/src/main/java/org/karnak/backend/model/Series.java b/src/main/java/org/karnak/backend/model/Series.java index d8779bfe5..8574fac11 100644 --- a/src/main/java/org/karnak/backend/model/Series.java +++ b/src/main/java/org/karnak/backend/model/Series.java @@ -20,9 +20,11 @@ public class Series { private final String seriesInstanceUID; + private final Map sopInstanceMap; private String seriesDescription; + private LocalDateTime seriesDate; public Series(String seriesInstanceUID) { diff --git a/src/main/java/org/karnak/backend/model/SopInstance.java b/src/main/java/org/karnak/backend/model/SopInstance.java index f36456add..579c91553 100644 --- a/src/main/java/org/karnak/backend/model/SopInstance.java +++ b/src/main/java/org/karnak/backend/model/SopInstance.java @@ -15,8 +15,11 @@ public class SopInstance { private final String sopInstanceUID; + private Integer instanceNumber; + private String sopClassUID; + private boolean sent; public SopInstance(String sopInstanceUID) { diff --git a/src/main/java/org/karnak/backend/model/SourceNode.java b/src/main/java/org/karnak/backend/model/SourceNode.java index a9f7197ee..6bb0bab80 100644 --- a/src/main/java/org/karnak/backend/model/SourceNode.java +++ b/src/main/java/org/karnak/backend/model/SourceNode.java @@ -14,6 +14,7 @@ public class SourceNode { private final String forwardAETitle; + private final DicomNode sourceNode; public SourceNode(String forwardAETitle, DicomNode sourceNode) { diff --git a/src/main/java/org/karnak/backend/model/Study.java b/src/main/java/org/karnak/backend/model/Study.java index 6f7aa696a..196b9beea 100644 --- a/src/main/java/org/karnak/backend/model/Study.java +++ b/src/main/java/org/karnak/backend/model/Study.java @@ -20,12 +20,19 @@ public class Study { private final String studyInstanceUID; + private final Map seriesMap; + private String patientID; + private String[] otherPatientIDs; + private String studyDescription; + private String accessionNumber; + private LocalDateTime studyDate; + private long timeStamp; public Study(String studyInstanceUID, String patientID) { diff --git a/src/main/java/org/karnak/backend/model/action/AbstractAction.java b/src/main/java/org/karnak/backend/model/action/AbstractAction.java index 928218162..c7ed5210f 100644 --- a/src/main/java/org/karnak/backend/model/action/AbstractAction.java +++ b/src/main/java/org/karnak/backend/model/action/AbstractAction.java @@ -18,16 +18,24 @@ import org.weasis.core.util.StringUtil; public abstract class AbstractAction implements ActionItem { + protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractAction.class); + protected static final Marker CLINICAL_MARKER = MarkerFactory.getMarker("CLINICAL"); + protected static final String PATTERN_WITH_INOUT = "SOPInstanceUID_OLD={} TAG={} ACTION={} OLD={} NEW={}"; + protected static final String PATTERN_WITH_IN = "SOPInstanceUID_OLD={} TAG={} ACTION={} OLD={}"; + protected static final String ADD_METHOD = "a"; protected final String symbol; + protected String dummyValue; + protected int newTag; + protected VR vr; protected AbstractAction(String symbol) { diff --git a/src/main/java/org/karnak/backend/model/action/MultipleActions.java b/src/main/java/org/karnak/backend/model/action/MultipleActions.java index 7ddf69388..1cce5a197 100644 --- a/src/main/java/org/karnak/backend/model/action/MultipleActions.java +++ b/src/main/java/org/karnak/backend/model/action/MultipleActions.java @@ -24,13 +24,19 @@ import org.slf4j.LoggerFactory; public class MultipleActions extends AbstractAction { + private static final Logger LOGGER = LoggerFactory.getLogger(MultipleActions.class); final StandardDICOM standardDICOM; + final ActionItem defaultDummyValue; + final ActionItem actionUID; + final ActionItem actionReplaceNull; + final ActionItem actionRemove; + final ActionItem actionKeep; public MultipleActions(String symbol) { @@ -153,10 +159,10 @@ private ActionItem dummyOrReplaceNullOrRemove(String currentType) { } private ActionItem replaceNullOrRemove(String currentType) { - /* TODO: throw exception ? - if (currentType.equals("1") || currentType.equals("1C")) { - throw new Exception(For the current SOP, the tag must type 1. Impossible to execute and respect the standard); - } + /* + * TODO: throw exception ? if (currentType.equals("1") || + * currentType.equals("1C")) { throw new Exception(For the current SOP, the tag + * must type 1. Impossible to execute and respect the standard); } */ if (currentType.equals("2") || currentType.equals("2C")) { return actionReplaceNull; diff --git a/src/main/java/org/karnak/backend/model/dicom/ConfigNode.java b/src/main/java/org/karnak/backend/model/dicom/ConfigNode.java index d872365ba..d63f1a96e 100644 --- a/src/main/java/org/karnak/backend/model/dicom/ConfigNode.java +++ b/src/main/java/org/karnak/backend/model/dicom/ConfigNode.java @@ -16,6 +16,7 @@ public class ConfigNode { private String name; + private DicomNode calledNode; public ConfigNode(String name, DicomNode calledNode) { diff --git a/src/main/java/org/karnak/backend/model/dicom/DicomEchoQueryData.java b/src/main/java/org/karnak/backend/model/dicom/DicomEchoQueryData.java index ae0888fae..c0cc2658d 100644 --- a/src/main/java/org/karnak/backend/model/dicom/DicomEchoQueryData.java +++ b/src/main/java/org/karnak/backend/model/dicom/DicomEchoQueryData.java @@ -14,9 +14,13 @@ public class DicomEchoQueryData { private static final String DEFAULT_VALUE_FOR_CALLING_AET = "DCM-TOOLS"; private String callingAet; + private DicomNodeList calledDicomNodeType; + private String calledAet; + private String calledHostname; + private Integer calledPort; public DicomEchoQueryData() { diff --git a/src/main/java/org/karnak/backend/model/dicom/Message.java b/src/main/java/org/karnak/backend/model/dicom/Message.java index 7748955ef..68a91989f 100644 --- a/src/main/java/org/karnak/backend/model/dicom/Message.java +++ b/src/main/java/org/karnak/backend/model/dicom/Message.java @@ -15,7 +15,9 @@ public class Message { private MessageLevel level; + private MessageFormat format; + private String text; public Message(MessageLevel level, MessageFormat format, String text) { diff --git a/src/main/java/org/karnak/backend/model/dicom/WadoNode.java b/src/main/java/org/karnak/backend/model/dicom/WadoNode.java index 7506f2596..7666c3849 100644 --- a/src/main/java/org/karnak/backend/model/dicom/WadoNode.java +++ b/src/main/java/org/karnak/backend/model/dicom/WadoNode.java @@ -17,7 +17,9 @@ public class WadoNode { private final String name; + private final URL url; + private final List tagEntities = new ArrayList(2); public WadoNode(String name, URL url) { diff --git a/src/main/java/org/karnak/backend/model/dicom/WorkListQueryData.java b/src/main/java/org/karnak/backend/model/dicom/WorkListQueryData.java index 8a87ea6f6..48ac4c520 100644 --- a/src/main/java/org/karnak/backend/model/dicom/WorkListQueryData.java +++ b/src/main/java/org/karnak/backend/model/dicom/WorkListQueryData.java @@ -17,16 +17,27 @@ public class WorkListQueryData { private static final String DEFAULT_VALUE_FOR_CALLING_AET = "DCM-TOOLS"; private String callingAet; + private String workListAet; + private String workListHostname; + private Integer workListPort; + private String scheduledStationAet; + private Modality scheduledModality; + private String patientId; + private String admissionId; + private LocalDate scheduledFrom; + private LocalDate scheduledTo; + private String patientName; + private String accessionNumber; public WorkListQueryData() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardAttributes.java b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardAttributes.java index 60e4e94b7..0e14833f7 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardAttributes.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardAttributes.java @@ -17,9 +17,11 @@ import java.nio.charset.StandardCharsets; public class StandardAttributes { + private static final String ATTRIBUTES_FILENAME = "attributes.json"; - private StandardAttributes() {} + private StandardAttributes() { + } public static jsonAttributes[] readJsonAttributes() { URL url = StandardCIODS.class.getResource(ATTRIBUTES_FILENAME); diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardCIODS.java b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardCIODS.java index 6458ad0eb..1ea76f3b1 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardCIODS.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardCIODS.java @@ -19,6 +19,7 @@ public class StandardCIODS { private static final String ciodsFileName = "ciods.json"; + private static jsonCIOD[] ciods; public StandardCIODS() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardCIODtoModules.java b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardCIODtoModules.java index 89e9c9872..e2c9c5b66 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardCIODtoModules.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardCIODtoModules.java @@ -19,6 +19,7 @@ public class StandardCIODtoModules { private static final String ciodToModulesFileName = "ciod_to_modules.json"; + private static jsonCIODtoModule[] ciodToModules; public StandardCIODtoModules() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardConfidentialityProfiles.java b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardConfidentialityProfiles.java index 1eaaf117f..66ec78fcb 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardConfidentialityProfiles.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardConfidentialityProfiles.java @@ -20,6 +20,7 @@ public class StandardConfidentialityProfiles { private static final String confidentialityProfilesFileName = "confidentiality_profile_attributes.json"; + private static jsonConfidentialityProfiles[] confidentialityProfiles; public StandardConfidentialityProfiles() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardModuleToAttributes.java b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardModuleToAttributes.java index e2116ca7f..21efc2439 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardModuleToAttributes.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardModuleToAttributes.java @@ -19,6 +19,7 @@ public class StandardModuleToAttributes { private static final String moduleToAttributesFileName = "module_to_attributes.json"; + private static jsonModuleToAttribute[] moduleToAttributes; public StandardModuleToAttributes() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardSOPS.java b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardSOPS.java index a39bd4764..b2148ef5f 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/StandardSOPS.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/StandardSOPS.java @@ -19,6 +19,7 @@ public class StandardSOPS { private static final String sopsFileName = "sops.json"; + private static jsonSOP[] sops; public StandardSOPS() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonAttributes.java b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonAttributes.java index 7261bec59..a49f572a5 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonAttributes.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonAttributes.java @@ -10,12 +10,19 @@ package org.karnak.backend.model.dicominnolitics; public class jsonAttributes { + private String tag; + private String name; + private String keyword; + private String valueRepresentation; + private String valueMultiplicity; + private String retired; + private String id; public String getTag() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonCIOD.java b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonCIOD.java index ba51cb9ca..dc200a132 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonCIOD.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonCIOD.java @@ -12,8 +12,11 @@ public class jsonCIOD { private String name; + private String id; + private String description; + private String linkToStandard; public String getName() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonCIODtoModule.java b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonCIODtoModule.java index d0ad9dea9..9dc31a972 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonCIODtoModule.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonCIODtoModule.java @@ -12,9 +12,13 @@ public class jsonCIODtoModule { private String ciodId; + private String moduleId; + private String usage; + private String conditionalStatement; + private String informationEntity; public String getCiodId() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonConfidentialityProfiles.java b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonConfidentialityProfiles.java index ecf5303e0..c162dfc76 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonConfidentialityProfiles.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonConfidentialityProfiles.java @@ -19,11 +19,17 @@ import org.karnak.backend.model.action.UID; public class jsonConfidentialityProfiles { + private String id; + private String name; + private String tag; + private String basicProfile; + private String stdCompIOD; + private String cleanDescOpt; public String getId() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonModuleToAttribute.java b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonModuleToAttribute.java index f872ec90c..34c715955 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonModuleToAttribute.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonModuleToAttribute.java @@ -12,10 +12,15 @@ public class jsonModuleToAttribute { private String moduleId; + private String path; + private String tag; + private String type; + private String linkToStandard; + private String description; public String getModuleId() { diff --git a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonSOP.java b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonSOP.java index ebcae0165..1b728d89f 100644 --- a/src/main/java/org/karnak/backend/model/dicominnolitics/jsonSOP.java +++ b/src/main/java/org/karnak/backend/model/dicominnolitics/jsonSOP.java @@ -12,7 +12,9 @@ public class jsonSOP { private String name; + private String id; + private String ciod; public String getName() { diff --git a/src/main/java/org/karnak/backend/model/echo/DestinationEcho.java b/src/main/java/org/karnak/backend/model/echo/DestinationEcho.java index 85194c1fb..53e995a71 100644 --- a/src/main/java/org/karnak/backend/model/echo/DestinationEcho.java +++ b/src/main/java/org/karnak/backend/model/echo/DestinationEcho.java @@ -12,25 +12,32 @@ import com.fasterxml.jackson.annotation.JsonInclude; import java.util.Objects; -/** Model for destination in echo controller */ +/** + * Model for destination in echo controller + */ @JsonInclude(JsonInclude.Include.NON_NULL) public class DestinationEcho { // AeTitle of the destination dicom private String aet; + // Url of the destination stow private String url; + // Status private int status; - /** Constructor without parameter */ - public DestinationEcho() {} + /** + * Constructor without parameter + */ + public DestinationEcho() { + } /** * Constructor with parameters * - * @param aet AeTitle - * @param url Url + * @param aet AeTitle + * @param url Url * @param status Status */ public DestinationEcho(String aet, String url, int status) { diff --git a/src/main/java/org/karnak/backend/model/editor/ConditionEditor.java b/src/main/java/org/karnak/backend/model/editor/ConditionEditor.java index 8c616832d..e75be7b9f 100644 --- a/src/main/java/org/karnak/backend/model/editor/ConditionEditor.java +++ b/src/main/java/org/karnak/backend/model/editor/ConditionEditor.java @@ -17,7 +17,8 @@ import org.weasis.dicom.param.AttributeEditorContext.Abort; public class ConditionEditor implements AttributeEditor { - private String condition; + + private final String condition; public ConditionEditor(String condition) { this.condition = condition; diff --git a/src/main/java/org/karnak/backend/model/editor/DeIdentifyEditor.java b/src/main/java/org/karnak/backend/model/editor/DeIdentifyEditor.java index 8bf1a4558..b0601408f 100644 --- a/src/main/java/org/karnak/backend/model/editor/DeIdentifyEditor.java +++ b/src/main/java/org/karnak/backend/model/editor/DeIdentifyEditor.java @@ -12,6 +12,7 @@ import org.dcm4che3.data.Attributes; import org.karnak.backend.data.entity.DestinationEntity; import org.karnak.backend.data.entity.ProfileEntity; +import org.karnak.backend.data.entity.ProjectEntity; import org.karnak.backend.service.profilepipe.Profile; import org.weasis.dicom.param.AttributeEditor; import org.weasis.dicom.param.AttributeEditorContext; @@ -20,19 +21,24 @@ public class DeIdentifyEditor implements AttributeEditor { private final Profile profile; - private DestinationEntity destinationEntity; - private ProfileEntity profileEntity; + + private final DestinationEntity destinationEntity; + + private final ProfileEntity profileEntity; + + private final ProjectEntity projectEntity; public DeIdentifyEditor(DestinationEntity destinationEntity) { this.destinationEntity = destinationEntity; - this.profileEntity = destinationEntity.getProjectEntity().getProfileEntity(); + this.projectEntity = destinationEntity.getDeIdentificationProjectEntity(); + this.profileEntity = projectEntity.getProfileEntity(); this.profile = new Profile(profileEntity); } @Override public void apply(Attributes dcm, AttributeEditorContext context) { if (context.getAbort() != Abort.FILE_EXCEPTION) { - profile.apply(dcm, destinationEntity, profileEntity, context); + profile.applyDeIdentification(dcm, destinationEntity, profileEntity, context, projectEntity); } } } diff --git a/src/main/java/org/karnak/backend/model/editor/FilterEditor.java b/src/main/java/org/karnak/backend/model/editor/FilterEditor.java index a26749e2e..c250e93c2 100644 --- a/src/main/java/org/karnak/backend/model/editor/FilterEditor.java +++ b/src/main/java/org/karnak/backend/model/editor/FilterEditor.java @@ -20,7 +20,7 @@ public class FilterEditor implements AttributeEditor { - private Set sopClassUIDEntitySet; + private final Set sopClassUIDEntitySet; public FilterEditor(Set sopClassUIDEntitySet) { this.sopClassUIDEntitySet = sopClassUIDEntitySet; diff --git a/src/main/java/org/karnak/backend/model/editor/StreamRegistryEditor.java b/src/main/java/org/karnak/backend/model/editor/StreamRegistryEditor.java index d211f84a5..39c5b3f74 100644 --- a/src/main/java/org/karnak/backend/model/editor/StreamRegistryEditor.java +++ b/src/main/java/org/karnak/backend/model/editor/StreamRegistryEditor.java @@ -34,10 +34,13 @@ public class StreamRegistryEditor implements AttributeEditor { private static final Logger LOGGER = LoggerFactory.getLogger(StreamRegistryEditor.class); + private final Map studyMap = new HashMap<>(); + private boolean enable = false; - public StreamRegistryEditor() {} + public StreamRegistryEditor() { + } private static LocalDateTime getDateTime(Attributes dicom, int date, int time) { LocalDate d = DateUtil.getDicomDate(dicom.getString(date)); diff --git a/src/main/java/org/karnak/backend/model/editor/TagMorphingEditor.java b/src/main/java/org/karnak/backend/model/editor/TagMorphingEditor.java new file mode 100644 index 000000000..bef6c3db8 --- /dev/null +++ b/src/main/java/org/karnak/backend/model/editor/TagMorphingEditor.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 Karnak Team and other contributors. + * + * This program and the accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which is available at https://www.eclipse.org/legal/epl-2.0, or the Apache + * License, Version 2.0 which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + */ +package org.karnak.backend.model.editor; + +import org.dcm4che3.data.Attributes; +import org.karnak.backend.data.entity.DestinationEntity; +import org.karnak.backend.data.entity.ProfileEntity; +import org.karnak.backend.data.entity.ProjectEntity; +import org.karnak.backend.service.profilepipe.Profile; +import org.weasis.dicom.param.AttributeEditor; +import org.weasis.dicom.param.AttributeEditorContext; +import org.weasis.dicom.param.AttributeEditorContext.Abort; + +public class TagMorphingEditor implements AttributeEditor { + + private final Profile profile; + + private final DestinationEntity destinationEntity; + + private final ProfileEntity profileEntity; + + private final ProjectEntity projectEntity; + + public TagMorphingEditor(DestinationEntity destinationEntity) { + this.destinationEntity = destinationEntity; + this.projectEntity = destinationEntity.getTagMorphingProjectEntity(); + this.profileEntity = projectEntity.getProfileEntity(); + this.profile = new Profile(profileEntity); + } + + @Override + public void apply(Attributes dcm, AttributeEditorContext context) { + if (context.getAbort() != Abort.FILE_EXCEPTION) { + profile.applyTagMorphing(dcm, destinationEntity, profileEntity, context, projectEntity); + } + } +} diff --git a/src/main/java/org/karnak/backend/model/event/NodeEvent.java b/src/main/java/org/karnak/backend/model/event/NodeEvent.java index 4d6052a84..9a8a1a4f3 100644 --- a/src/main/java/org/karnak/backend/model/event/NodeEvent.java +++ b/src/main/java/org/karnak/backend/model/event/NodeEvent.java @@ -17,9 +17,11 @@ import org.springframework.context.ApplicationEvent; public class NodeEvent extends ApplicationEvent { + private static final long serialVersionUID = -15504960651765311L; private final NodeEventType eventType; + private final ForwardNodeEntity forwardNodeEntity; public NodeEvent(ForwardNodeEntity fwdNode, NodeEventType eventType) { diff --git a/src/main/java/org/karnak/backend/model/event/TransferMonitoringEvent.java b/src/main/java/org/karnak/backend/model/event/TransferMonitoringEvent.java index d8ce09cf7..536a188b2 100644 --- a/src/main/java/org/karnak/backend/model/event/TransferMonitoringEvent.java +++ b/src/main/java/org/karnak/backend/model/event/TransferMonitoringEvent.java @@ -12,7 +12,9 @@ import org.karnak.backend.data.entity.TransferStatusEntity; import org.springframework.context.ApplicationEvent; -/** Transfer monitoring event used to populate asynchronously transfer_status table */ +/** + * Transfer monitoring event used to populate asynchronously transfer_status table + */ public class TransferMonitoringEvent extends ApplicationEvent { public TransferMonitoringEvent(TransferStatusEntity transferStatusEntity) { diff --git a/src/main/java/org/karnak/backend/model/expression/ExprAction.java b/src/main/java/org/karnak/backend/model/expression/ExprAction.java index 94ef6013e..4d994e7cc 100644 --- a/src/main/java/org/karnak/backend/model/expression/ExprAction.java +++ b/src/main/java/org/karnak/backend/model/expression/ExprAction.java @@ -24,9 +24,13 @@ public class ExprAction implements ExpressionItem { private int tag; + private VR vr; + private String stringValue; + private Attributes dcm; + private Attributes dcmCopy; public ExprAction(int tag, VR vr, Attributes dcm, Attributes dcmCopy) { @@ -106,9 +110,10 @@ public boolean tagIsPresent(int tag) { return DicomObjectTools.containsTagInAllAttributes(tag, dcmCopy); } - /*public ActionItem Add(int newTag, VR newVr, String newValue){ - Add add = new Add("A", newTag, newVr, newValue); - add.execute(dcm, newTag, null, null); - return null; - }*/ + /* + * public ActionItem Add(int newTag, VR newVr, String newValue){ Add add = new + * Add("A", newTag, newVr, newValue); add.execute(dcm, newTag, null, null); return + * null; } + */ + } diff --git a/src/main/java/org/karnak/backend/model/expression/ExpressionError.java b/src/main/java/org/karnak/backend/model/expression/ExpressionError.java index 8bbb11111..7df1ba6e3 100644 --- a/src/main/java/org/karnak/backend/model/expression/ExpressionError.java +++ b/src/main/java/org/karnak/backend/model/expression/ExpressionError.java @@ -12,6 +12,7 @@ public class ExpressionError { private boolean isValid; + private String msg; public ExpressionError(boolean isValid, String msg) { diff --git a/src/main/java/org/karnak/backend/model/expression/ExpressionItem.java b/src/main/java/org/karnak/backend/model/expression/ExpressionItem.java index b1df15b64..4add8bd98 100644 --- a/src/main/java/org/karnak/backend/model/expression/ExpressionItem.java +++ b/src/main/java/org/karnak/backend/model/expression/ExpressionItem.java @@ -9,4 +9,6 @@ */ package org.karnak.backend.model.expression; -public interface ExpressionItem {} +public interface ExpressionItem { + +} diff --git a/src/main/java/org/karnak/backend/model/image/TransformedPlanarImage.java b/src/main/java/org/karnak/backend/model/image/TransformedPlanarImage.java new file mode 100644 index 000000000..cb699e3dc --- /dev/null +++ b/src/main/java/org/karnak/backend/model/image/TransformedPlanarImage.java @@ -0,0 +1,27 @@ +package org.karnak.backend.model.image; + +import org.dcm4che3.img.util.Editable; +import org.weasis.opencv.data.PlanarImage; + +public class TransformedPlanarImage { + + Editable editablePlanarImage; + PlanarImage planarImage; + + public Editable getEditablePlanarImage() { + return editablePlanarImage; + } + + public void setEditablePlanarImage( + Editable editablePlanarImage) { + this.editablePlanarImage = editablePlanarImage; + } + + public PlanarImage getPlanarImage() { + return planarImage; + } + + public void setPlanarImage(PlanarImage planarImage) { + this.planarImage = planarImage; + } +} diff --git a/src/main/java/org/karnak/backend/model/kheops/MetadataSwitching.java b/src/main/java/org/karnak/backend/model/kheops/MetadataSwitching.java index 29bcf6cdd..a6c6bf284 100644 --- a/src/main/java/org/karnak/backend/model/kheops/MetadataSwitching.java +++ b/src/main/java/org/karnak/backend/model/kheops/MetadataSwitching.java @@ -12,8 +12,11 @@ public class MetadataSwitching { private final String studyInstanceUID; + private final String seriesInstanceUID; + private final String SOPinstanceUID; + private boolean applied; public MetadataSwitching( diff --git a/src/main/java/org/karnak/backend/model/notification/SerieSummaryNotification.java b/src/main/java/org/karnak/backend/model/notification/SerieSummaryNotification.java index 9d9725921..3c46fa0b1 100644 --- a/src/main/java/org/karnak/backend/model/notification/SerieSummaryNotification.java +++ b/src/main/java/org/karnak/backend/model/notification/SerieSummaryNotification.java @@ -14,14 +14,21 @@ import java.util.Objects; import org.karnak.backend.constant.Notification; -/** Model used for serie summary notification */ +/** + * Model used for serie summary notification + */ public class SerieSummaryNotification { private String serieUid; + private String serieDescription; + private LocalDateTime serieDate; + private long nbTransferSent; + private long nbTransferNotSent; + private List unTransferedReasons; public String getSerieUid() { diff --git a/src/main/java/org/karnak/backend/model/notification/TransferMonitoringNotification.java b/src/main/java/org/karnak/backend/model/notification/TransferMonitoringNotification.java index 87d417e5b..3c4325fc2 100644 --- a/src/main/java/org/karnak/backend/model/notification/TransferMonitoringNotification.java +++ b/src/main/java/org/karnak/backend/model/notification/TransferMonitoringNotification.java @@ -13,19 +13,31 @@ import java.util.List; import java.util.Objects; -/** Model used to build transfer monitoring notification */ +/** + * Model used to build transfer monitoring notification + */ public class TransferMonitoringNotification { private String subject; + private String from; + private String to; + private String patientId; + private String studyUid; + private String accessionNumber; + private String studyDescription; + private LocalDateTime studyDate; + private String source; + private String destination; + private List serieSummaryNotifications; public String getSubject() { diff --git a/src/main/java/org/karnak/backend/model/profilebody/MaskBody.java b/src/main/java/org/karnak/backend/model/profilebody/MaskBody.java index 5f81740a0..0b58a1bc4 100644 --- a/src/main/java/org/karnak/backend/model/profilebody/MaskBody.java +++ b/src/main/java/org/karnak/backend/model/profilebody/MaskBody.java @@ -14,7 +14,9 @@ public class MaskBody { private String stationName; + private String color; + private List rectangles; public String getStationName() { diff --git a/src/main/java/org/karnak/backend/model/profilebody/ProfileElementBody.java b/src/main/java/org/karnak/backend/model/profilebody/ProfileElementBody.java index 3450b3e76..55b7c5647 100644 --- a/src/main/java/org/karnak/backend/model/profilebody/ProfileElementBody.java +++ b/src/main/java/org/karnak/backend/model/profilebody/ProfileElementBody.java @@ -15,13 +15,21 @@ public class ProfileElementBody { private String name; + private String codename; + private String condition; + private String action; + private String option; + private String args; + private List tagEntities; + private List excludedTags; + private Map arguments; public String getName() { diff --git a/src/main/java/org/karnak/backend/model/profilebody/ProfilePipeBody.java b/src/main/java/org/karnak/backend/model/profilebody/ProfilePipeBody.java index 42abfb7f8..3c2b46959 100644 --- a/src/main/java/org/karnak/backend/model/profilebody/ProfilePipeBody.java +++ b/src/main/java/org/karnak/backend/model/profilebody/ProfilePipeBody.java @@ -14,10 +14,15 @@ public class ProfilePipeBody { private String name; + private String version; + private String minimumKarnakVersion; + private String defaultIssuerOfPatientID; + private List profiles; + private List masks; public String getName() { diff --git a/src/main/java/org/karnak/backend/model/profilepipe/HMAC.java b/src/main/java/org/karnak/backend/model/profilepipe/HMAC.java index 310b13ab6..46c143788 100644 --- a/src/main/java/org/karnak/backend/model/profilepipe/HMAC.java +++ b/src/main/java/org/karnak/backend/model/profilepipe/HMAC.java @@ -25,10 +25,13 @@ public class HMAC { public static final int KEY_BYTE_LENGTH = 16; + private static final Logger LOGGER = LoggerFactory.getLogger(HMAC.class); + private static final String HMAC_SHA256 = "HmacSHA256"; private Mac mac; + private HashContext hashContext; public HMAC(byte[] hmacKey) { @@ -42,7 +45,7 @@ public HMAC(HashContext hashContext) { /* * Generate a random secret key of 32bytes - * */ + */ public static byte[] generateRandomKey() { SecureRandom random = new SecureRandom(); byte[] bytes = new byte[KEY_BYTE_LENGTH]; @@ -117,7 +120,7 @@ public String uidHash(String inputUID) { // Variant 1 -> 10b uuid[8] &= 0x3F; uuid[8] |= 0x80; - return "2.25." + new BigInteger(1, uuid).toString(); + return "2.25." + new BigInteger(1, uuid); } public HashContext getHashContext() { diff --git a/src/main/java/org/karnak/backend/model/profilepipe/HashContext.java b/src/main/java/org/karnak/backend/model/profilepipe/HashContext.java index 9f8c616bc..53e4577cd 100644 --- a/src/main/java/org/karnak/backend/model/profilepipe/HashContext.java +++ b/src/main/java/org/karnak/backend/model/profilepipe/HashContext.java @@ -12,6 +12,7 @@ public class HashContext { private final byte[] secret; + private final String PatientID; public HashContext(byte[] secret, String PatientID) { diff --git a/src/main/java/org/karnak/backend/model/profilepipe/PatientMetadata.java b/src/main/java/org/karnak/backend/model/profilepipe/PatientMetadata.java index b4cafd4ae..598190561 100644 --- a/src/main/java/org/karnak/backend/model/profilepipe/PatientMetadata.java +++ b/src/main/java/org/karnak/backend/model/profilepipe/PatientMetadata.java @@ -13,7 +13,7 @@ import org.dcm4che3.data.Attributes; import org.dcm4che3.data.Tag; import org.karnak.backend.api.rqbody.Fields; -import org.karnak.backend.cache.PseudonymPatient; +import org.karnak.backend.cache.Patient; import org.weasis.dicom.util.DateUtil; public class PatientMetadata { @@ -21,9 +21,13 @@ public class PatientMetadata { private static final String PATIENT_SEX_OTHER = "O"; private final String patientID; + private final String patientName; + private final String patientBirthDate; + private final String issuerOfPatientID; + private final String patientSex; public PatientMetadata(Attributes dcm) { @@ -89,13 +93,13 @@ public String getPatientSex() { return patientSex; } - public boolean compareCachedPatient(PseudonymPatient patient) { + public boolean compareCachedPatient(Patient patient) { if (patient != null) { boolean samePatient = patient.getPatientId().equals(patientID); samePatient = samePatient && (patient.getIssuerOfPatientId() == null - || patient.getIssuerOfPatientId().equals(issuerOfPatientID)); + || patient.getIssuerOfPatientId().equals(issuerOfPatientID)); return samePatient; } return false; diff --git a/src/main/java/org/karnak/backend/model/profilepipe/TagActionMap.java b/src/main/java/org/karnak/backend/model/profilepipe/TagActionMap.java index 8127418be..65292c164 100644 --- a/src/main/java/org/karnak/backend/model/profilepipe/TagActionMap.java +++ b/src/main/java/org/karnak/backend/model/profilepipe/TagActionMap.java @@ -18,6 +18,7 @@ public class TagActionMap { private final HashMap tagAction; + private final HashMap tagPatternAction; public TagActionMap() { diff --git a/src/main/java/org/karnak/backend/model/profiles/AbstractProfileItem.java b/src/main/java/org/karnak/backend/model/profiles/AbstractProfileItem.java index 57aecf4f2..17cd30002 100644 --- a/src/main/java/org/karnak/backend/model/profiles/AbstractProfileItem.java +++ b/src/main/java/org/karnak/backend/model/profiles/AbstractProfileItem.java @@ -25,14 +25,23 @@ public abstract class AbstractProfileItem implements ProfileItem { protected final String name; + protected final String codeName; + protected final String condition; + protected final String action; + protected final String option; + protected final List argumentEntities; + protected final List tagEntities; + protected final List excludedTagEntities; + protected final Map tagMap; + protected final Integer position; protected AbstractProfileItem(ProfileElementEntity profileElementEntity) { diff --git a/src/main/java/org/karnak/backend/model/profiles/ActionDates.java b/src/main/java/org/karnak/backend/model/profiles/ActionDates.java index 76972c7e6..a5942f7a5 100644 --- a/src/main/java/org/karnak/backend/model/profiles/ActionDates.java +++ b/src/main/java/org/karnak/backend/model/profiles/ActionDates.java @@ -34,7 +34,9 @@ public class ActionDates extends AbstractProfileItem { private static final Logger LOGGER = LoggerFactory.getLogger(ActionDates.class); private final TagActionMap tagsAction; + private final TagActionMap exceptedTagsAction; + private final ActionItem actionByDefault; public ActionDates(ProfileElementEntity profileElementEntity) throws Exception { diff --git a/src/main/java/org/karnak/backend/model/profiles/ActionTags.java b/src/main/java/org/karnak/backend/model/profiles/ActionTags.java index 833116aa2..4ca741cea 100644 --- a/src/main/java/org/karnak/backend/model/profiles/ActionTags.java +++ b/src/main/java/org/karnak/backend/model/profiles/ActionTags.java @@ -29,7 +29,9 @@ public class ActionTags extends AbstractProfileItem { private static final Logger LOGGER = LoggerFactory.getLogger(ActionTags.class); private final TagActionMap tagsAction; + private final TagActionMap exceptedTagsAction; + private final ActionItem actionByDefault; public ActionTags(ProfileElementEntity profileElementEntity) throws Exception { diff --git a/src/main/java/org/karnak/backend/model/profiles/BasicProfile.java b/src/main/java/org/karnak/backend/model/profiles/BasicProfile.java index 24f930b18..0df79f81a 100644 --- a/src/main/java/org/karnak/backend/model/profiles/BasicProfile.java +++ b/src/main/java/org/karnak/backend/model/profiles/BasicProfile.java @@ -21,6 +21,7 @@ public class BasicProfile extends AbstractProfileItem { private final List listProfiles; + private final TagActionMap actionMap; public BasicProfile(ProfileElementEntity profileElementEntity) { diff --git a/src/main/java/org/karnak/backend/model/profiles/Expression.java b/src/main/java/org/karnak/backend/model/profiles/Expression.java index 70a1cecea..18a43d165 100644 --- a/src/main/java/org/karnak/backend/model/profiles/Expression.java +++ b/src/main/java/org/karnak/backend/model/profiles/Expression.java @@ -28,7 +28,9 @@ public class Expression extends AbstractProfileItem { private final TagActionMap tagsAction; + private final TagActionMap exceptedTagsAction; + private final ActionItem actionByDefault; public Expression(ProfileElementEntity profileElementEntity) throws Exception { diff --git a/src/main/java/org/karnak/backend/model/profiles/PrivateTags.java b/src/main/java/org/karnak/backend/model/profiles/PrivateTags.java index cb873b701..da3798432 100644 --- a/src/main/java/org/karnak/backend/model/profiles/PrivateTags.java +++ b/src/main/java/org/karnak/backend/model/profiles/PrivateTags.java @@ -29,7 +29,9 @@ public class PrivateTags extends AbstractProfileItem { private static final Logger LOGGER = LoggerFactory.getLogger(PrivateTags.class); private final TagActionMap tagsAction; + private final TagActionMap exceptedTagsAction; + private final ActionItem actionByDefault; public PrivateTags(ProfileElementEntity profileElementEntity) throws Exception { diff --git a/src/main/java/org/karnak/backend/model/profiles/ProfileItem.java b/src/main/java/org/karnak/backend/model/profiles/ProfileItem.java index 191012f59..d70542434 100644 --- a/src/main/java/org/karnak/backend/model/profiles/ProfileItem.java +++ b/src/main/java/org/karnak/backend/model/profiles/ProfileItem.java @@ -16,6 +16,7 @@ import org.karnak.backend.model.profilepipe.HMAC; public interface ProfileItem { + ActionItem getAction(Attributes dcm, Attributes dcmCopy, int tag, HMAC hmac); ActionItem put(int tag, ActionItem action); diff --git a/src/main/java/org/karnak/backend/model/standard/AttributeDetail.java b/src/main/java/org/karnak/backend/model/standard/AttributeDetail.java index f24cd7c00..510830a84 100644 --- a/src/main/java/org/karnak/backend/model/standard/AttributeDetail.java +++ b/src/main/java/org/karnak/backend/model/standard/AttributeDetail.java @@ -10,12 +10,19 @@ package org.karnak.backend.model.standard; public class AttributeDetail { + private final String id; + private final String keyword; + private final String name; + private final String retired; + private final String tag; + private final String valueMultiplicity; + private final String valueRepresentation; public AttributeDetail( diff --git a/src/main/java/org/karnak/backend/model/standard/AttributeDetails.java b/src/main/java/org/karnak/backend/model/standard/AttributeDetails.java index 42249a9dc..a440608e1 100644 --- a/src/main/java/org/karnak/backend/model/standard/AttributeDetails.java +++ b/src/main/java/org/karnak/backend/model/standard/AttributeDetails.java @@ -17,6 +17,7 @@ import org.karnak.backend.model.dicominnolitics.jsonAttributes; public class AttributeDetails { + private final Map hmapAttributeDetail; public AttributeDetails() { diff --git a/src/main/java/org/karnak/backend/model/standard/ConfidentialityProfiles.java b/src/main/java/org/karnak/backend/model/standard/ConfidentialityProfiles.java index a158a0b24..c14f09cc4 100644 --- a/src/main/java/org/karnak/backend/model/standard/ConfidentialityProfiles.java +++ b/src/main/java/org/karnak/backend/model/standard/ConfidentialityProfiles.java @@ -29,6 +29,7 @@ public class ConfidentialityProfiles { private static final Logger LOGGER = LoggerFactory.getLogger(ConfidentialityProfiles.class); private final TagActionMap actionMap = new TagActionMap(); + private final List listProfiles = new ArrayList<>(); public ConfidentialityProfiles() { diff --git a/src/main/java/org/karnak/backend/model/standard/DICOMType.java b/src/main/java/org/karnak/backend/model/standard/DICOMType.java index e818231f6..3f1b24e7d 100644 --- a/src/main/java/org/karnak/backend/model/standard/DICOMType.java +++ b/src/main/java/org/karnak/backend/model/standard/DICOMType.java @@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory; public class DICOMType { + private static final Logger LOGGER = LoggerFactory.getLogger(DICOMType.class); public static String getBySOP(Attributes dcm, int tag) { diff --git a/src/main/java/org/karnak/backend/model/standard/Module.java b/src/main/java/org/karnak/backend/model/standard/Module.java index 690ea7985..a81ddd692 100644 --- a/src/main/java/org/karnak/backend/model/standard/Module.java +++ b/src/main/java/org/karnak/backend/model/standard/Module.java @@ -14,7 +14,9 @@ public class Module { public static final String MANDATORY = "M"; private final String id; + private final String usage; + private final String informationEntity; public Module(String id, String usage, String informationEntity) { diff --git a/src/main/java/org/karnak/backend/model/standard/ModuleAttribute.java b/src/main/java/org/karnak/backend/model/standard/ModuleAttribute.java index d1531304d..fe347ae12 100644 --- a/src/main/java/org/karnak/backend/model/standard/ModuleAttribute.java +++ b/src/main/java/org/karnak/backend/model/standard/ModuleAttribute.java @@ -17,9 +17,13 @@ public class ModuleAttribute { private static final List strictedTypes = Arrays.asList("1", "1C", "2", "2C", "3"); + private final String moduleTagPath; + private final String tagPath; + private final String type; + private final String moduleId; public ModuleAttribute(String moduleTagPath, String type, String moduleId) { diff --git a/src/main/java/org/karnak/backend/model/standard/ModuleToAttributes.java b/src/main/java/org/karnak/backend/model/standard/ModuleToAttributes.java index 84e7afd01..98fcb6b81 100644 --- a/src/main/java/org/karnak/backend/model/standard/ModuleToAttributes.java +++ b/src/main/java/org/karnak/backend/model/standard/ModuleToAttributes.java @@ -20,7 +20,7 @@ public class ModuleToAttributes { /* * > - * */ + */ private final Map> HMapModuleAttributes; public ModuleToAttributes() { diff --git a/src/main/java/org/karnak/backend/model/standard/SOP.java b/src/main/java/org/karnak/backend/model/standard/SOP.java index 2ea43c864..9d5b43bd0 100644 --- a/src/main/java/org/karnak/backend/model/standard/SOP.java +++ b/src/main/java/org/karnak/backend/model/standard/SOP.java @@ -14,9 +14,13 @@ public class SOP { private final String UID; + private final String name; + private final String ciod; + private final String ciod_id; + private final ArrayList modules; SOP(String UID, String name, String ciod, String ciod_id, ArrayList modules) { diff --git a/src/main/java/org/karnak/backend/model/standard/StandardDICOM.java b/src/main/java/org/karnak/backend/model/standard/StandardDICOM.java index 7cfee9ecc..05d0db06b 100644 --- a/src/main/java/org/karnak/backend/model/standard/StandardDICOM.java +++ b/src/main/java/org/karnak/backend/model/standard/StandardDICOM.java @@ -20,7 +20,9 @@ public class StandardDICOM { private final SOPS sops; + private final ModuleToAttributes moduleToAttributes; + private final AttributeDetails attributeDetails; public StandardDICOM() { diff --git a/src/main/java/org/karnak/backend/security/OpenIdConnectLogoutHandler.java b/src/main/java/org/karnak/backend/security/OpenIdConnectLogoutHandler.java index e67fc6325..9c99e6f05 100644 --- a/src/main/java/org/karnak/backend/security/OpenIdConnectLogoutHandler.java +++ b/src/main/java/org/karnak/backend/security/OpenIdConnectLogoutHandler.java @@ -20,12 +20,15 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; -/** Handle IDP logout */ +/** + * Handle IDP logout + */ public class OpenIdConnectLogoutHandler extends SecurityContextLogoutHandler { private static final Logger logger = LoggerFactory.getLogger(OpenIdConnectLogoutHandler.class); private static final String END_SESSION_ENDPOINT = "/protocol/openid-connect/logout"; + private static final String ID_TOKEN_HINT = "id_token_hint"; @Override diff --git a/src/main/java/org/karnak/backend/security/UIServiceInitListener.java b/src/main/java/org/karnak/backend/security/UIServiceInitListener.java index 319630b4a..cd8e1ac7a 100644 --- a/src/main/java/org/karnak/backend/security/UIServiceInitListener.java +++ b/src/main/java/org/karnak/backend/security/UIServiceInitListener.java @@ -86,11 +86,12 @@ private void beforeEnter(BeforeEnterEvent event) { && !isLoginScreen) { // If root requested if (isForwardNode) { - // List all authorized views and take first one if user request root of the application + // List all authorized views and take first one if user request root of + // the application // Try to find first authorized view Optional> firstAuthorizedViewFoundOpt = - viewClasses.stream().filter(SecurityUtil::isAccessGranted).findFirst(); + viewClasses.stream().filter(SecurityUtil::isAccessGranted).findFirst(); // If an authorized view have been found if (firstAuthorizedViewFoundOpt.isPresent()) { diff --git a/src/main/java/org/karnak/backend/service/CStoreSCPService.java b/src/main/java/org/karnak/backend/service/CStoreSCPService.java index 08c4f6ceb..352da115e 100644 --- a/src/main/java/org/karnak/backend/service/CStoreSCPService.java +++ b/src/main/java/org/karnak/backend/service/CStoreSCPService.java @@ -47,14 +47,18 @@ public class CStoreSCPService extends BasicCStoreSCP { // Service private final DestinationRepo destinationRepo; + private final ForwardService forwardService; private Map> destinations; + private volatile int priority; + private volatile int status = 0; // Scheduled service for updating status transfer in progress private ScheduledFuture isDelayOver; + private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); @@ -92,11 +96,11 @@ protected void store( boolean valid = srcNodes.isEmpty() || srcNodes.stream() - .anyMatch( - n -> - n.getAet().equals(callingNode.getAet()) - && (!n.isValidateHostname() - || n.equalsHostname(callingNode.getHostname()))); + .anyMatch( + n -> + n.getAet().equals(callingNode.getAet()) + && (!n.isValidateHostname() + || n.equalsHostname(callingNode.getHostname()))); if (!valid) { rsp.setInt(Tag.Status, VR.US, Status.NotAuthorized); LOGGER.error( @@ -151,7 +155,7 @@ private void updateTransferStatus(List destinations) { * Update the transfer status of a destination * * @param destination Destination to retrieve - * @param status Status to update + * @param status Status to update */ private void updateTransferStatus(ForwardDestination destination, boolean status) { // Retrieve the destination entity @@ -159,7 +163,8 @@ private void updateTransferStatus(ForwardDestination destination, boolean status destinationRepo.findById(destination.getId()); if (destinationEntityOptional.isPresent()) { - // Update the destination transfer status if destination has been found and destination + // Update the destination transfer status if destination has been found and + // destination // is active DestinationEntity destinationEntity = destinationEntityOptional.get(); if (destinationEntity.isActivate()) { diff --git a/src/main/java/org/karnak/backend/service/DestinationService.java b/src/main/java/org/karnak/backend/service/DestinationService.java index df66b5e09..453a1507e 100644 --- a/src/main/java/org/karnak/backend/service/DestinationService.java +++ b/src/main/java/org/karnak/backend/service/DestinationService.java @@ -19,7 +19,9 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -/** Service managing destinations */ +/** + * Service managing destinations + */ @Service public class DestinationService { @@ -28,6 +30,7 @@ public class DestinationService { // Services private final ForwardNodeService forwardNodeService; + private final KheopsAlbumsService kheopsAlbumsService; // Event publisher @@ -36,9 +39,9 @@ public class DestinationService { /** * Autowired constructor * - * @param destinationRepo Destination repository - * @param forwardNodeService ForwardNode Service - * @param kheopsAlbumsService Kheops Albums Service + * @param destinationRepo Destination repository + * @param forwardNodeService ForwardNode Service + * @param kheopsAlbumsService Kheops Albums Service * @param applicationEventPublisher ApplicationEventPublisher */ @Autowired @@ -65,7 +68,7 @@ public DestinationEntity save( forwardNodeService.updateDestination(forwardNodeEntity, destinationEntity); if (destinationEntity.getId() != null) { - dataUpdated = removeValuesOnDisabledDesidentification(destinationEntity); + dataUpdated = removeValuesOnDisabledDeIdentificationTagMorphing(destinationEntity); } // Refresh last transfer and email last check before saving @@ -93,10 +96,13 @@ public void refreshLastTransferEmailLastCheck(DestinationEntity destinationEntit } } - private DestinationEntity removeValuesOnDisabledDesidentification( + private DestinationEntity removeValuesOnDisabledDeIdentificationTagMorphing( DestinationEntity destinationEntity) { if (!destinationEntity.isDesidentification()) { - destinationEntity.setProjectEntity(null); + destinationEntity.setDeIdentificationProjectEntity(null); + } + if (!destinationEntity.isActivateTagMorphing()) { + destinationEntity.setTagMorphingProjectEntity(null); } return destinationEntity; } diff --git a/src/main/java/org/karnak/backend/service/DicomGatewayService.java b/src/main/java/org/karnak/backend/service/DicomGatewayService.java index 12131aa6f..e38520a9a 100644 --- a/src/main/java/org/karnak/backend/service/DicomGatewayService.java +++ b/src/main/java/org/karnak/backend/service/DicomGatewayService.java @@ -28,7 +28,9 @@ @Service public class DicomGatewayService { + private final StoreScpForwardService storeScpForwardService; + private DeviceListenerService deviceService; @Autowired @@ -39,9 +41,9 @@ public DicomGatewayService(final StoreScpForwardService storeScpForwardService) /** * Init a DICOM Gateway with one final destination * - * @param forwardParams the optional advanced parameters (proxy, authentication, connection and - * TLS) for the final destination - * @param fwdNode the calling DICOM node configuration + * @param forwardParams the optional advanced parameters (proxy, authentication, connection and + * TLS) for the final destination + * @param fwdNode the calling DICOM node configuration * @param destinationNode the final DICOM node configuration * @throws IOException */ @@ -54,11 +56,11 @@ public void init( /** * Init a DICOM Gateway with one final destination * - * @param forwardParams the optional advanced parameters (proxy, authentication, connection and - * TLS) for the final destination - * @param fwdNode the calling DICOM node configuration + * @param forwardParams the optional advanced parameters (proxy, authentication, connection and + * TLS) for the final destination + * @param fwdNode the calling DICOM node configuration * @param destinationNode the final DICOM node configuration - * @param editors the list of editor for modifying attributes on the fly (can be Null) + * @param editors the list of editor for modifying attributes on the fly (can be Null) * @throws IOException */ public void init( diff --git a/src/main/java/org/karnak/backend/service/EchoService.java b/src/main/java/org/karnak/backend/service/EchoService.java index f63c2dd59..a21a57f8b 100644 --- a/src/main/java/org/karnak/backend/service/EchoService.java +++ b/src/main/java/org/karnak/backend/service/EchoService.java @@ -27,7 +27,9 @@ import org.weasis.dicom.param.DicomNode; import org.weasis.dicom.param.DicomState; -/** Service managing echo */ +/** + * Service managing echo + */ @Service public class EchoService { @@ -44,8 +46,8 @@ public EchoService(final GatewaySetUpService gatewaySetUpService) { /** * Retrieve the configured destinations from the setup * - * @return List of configured destinations * @param sourceAet Source AeTitle + * @return List of configured destinations */ public List retrieveStatusConfiguredDestinations(String sourceAet) { List destinationEchos = new ArrayList<>(); @@ -65,8 +67,8 @@ public List retrieveStatusConfiguredDestinations(String sourceA * Fill the list of destinations status * * @param destinationEchos List to fill - * @param sourceNode Source Node - * @param destinations Destinations found + * @param sourceNode Source Node + * @param destinations Destinations found */ private void fillDestinationsStatus( List destinationEchos, @@ -98,7 +100,7 @@ else if (destination instanceof WebForwardDestination) { * Build params for echo process call * * @param connectTimeout Connect Timeout - * @param acceptTimeout Accept Timeout + * @param acceptTimeout Accept Timeout * @return parameters built */ private AdvancedParams buildEchoProcessParams(int connectTimeout, int acceptTimeout) { diff --git a/src/main/java/org/karnak/backend/service/FileService.java b/src/main/java/org/karnak/backend/service/FileService.java index 2356d7cc0..d149f1b30 100644 --- a/src/main/java/org/karnak/backend/service/FileService.java +++ b/src/main/java/org/karnak/backend/service/FileService.java @@ -14,46 +14,47 @@ // @Service // public class FileService { // -// private static final Logger LOGGER = LoggerFactory.getLogger(FileService.class); +// private static final Logger LOGGER = LoggerFactory.getLogger(FileService.class); // -// // Service -// private final GatewaySetUpService gatewaySetUpService; +// // Service +// private final GatewaySetUpService gatewaySetUpService; // -// @Autowired -// public FileService(final GatewaySetUpService gatewaySetUpService) { -// this.gatewaySetUpService = gatewaySetUpService; -// } +// @Autowired +// public FileService(final GatewaySetUpService gatewaySetUpService) { +// this.gatewaySetUpService = gatewaySetUpService; +// } // -// /** -// * Retrieve the file to download -// * -// * @param aet AeTitle -// * @param fileName File name -// * @return File to download -// * @throws IOException IO Exception -// * @throws IllegalStateException Illegal State Exception -// */ -// public byte[] retrieveFileToDownload(String aet, String fileName) -// throws IOException, IllegalStateException { +// /** +// * Retrieve the file to download +// * +// * @param aet AeTitle +// * @param fileName File name +// * @return File to download +// * @throws IOException IO Exception +// * @throws IllegalStateException Illegal State Exception +// */ +// public byte[] retrieveFileToDownload(String aet, String fileName) +// throws IOException, IllegalStateException { // -// // Stored Path to get file from -// final Path archiveDir = gatewaySetUpService.getStorePath(); +// // Stored Path to get file from +// final Path archiveDir = gatewaySetUpService.getStorePath(); // -// // If path is not valid throw an exception -// if (archiveDir == null || !Files.isDirectory(archiveDir) || !Files.isReadable(archiveDir)) { -// throw new IllegalStateException("Cannot access to the archive directory"); -// } else { -// if (aet != null && fileName != null) { -// Path path = Path.of(archiveDir.toString(), aet, fileName); -// if (path == null || !Files.isReadable(path)) { -// LOGGER.warn("Cannot get this file for downloading: {}", path); -// } else { -// // Return the file -// DataInputStream in = new DataInputStream(Files.newInputStream(path)); -// return IOUtils.toByteArray(in); -// } -// } -// } -// return null; -// } +// // If path is not valid throw an exception +// if (archiveDir == null || !Files.isDirectory(archiveDir) || +// !Files.isReadable(archiveDir)) { +// throw new IllegalStateException("Cannot access to the archive directory"); +// } else { +// if (aet != null && fileName != null) { +// Path path = Path.of(archiveDir.toString(), aet, fileName); +// if (path == null || !Files.isReadable(path)) { +// LOGGER.warn("Cannot get this file for downloading: {}", path); +// } else { +// // Return the file +// DataInputStream in = new DataInputStream(Files.newInputStream(path)); +// return IOUtils.toByteArray(in); +// } +// } +// } +// return null; +// } // } diff --git a/src/main/java/org/karnak/backend/service/ForwardNodeAPIService.java b/src/main/java/org/karnak/backend/service/ForwardNodeAPIService.java index 86668f97a..212833cc5 100644 --- a/src/main/java/org/karnak/backend/service/ForwardNodeAPIService.java +++ b/src/main/java/org/karnak/backend/service/ForwardNodeAPIService.java @@ -18,12 +18,15 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -/** Forward Node API Service */ +/** + * Forward Node API Service + */ @Service public class ForwardNodeAPIService implements Serializable { // Services private final ForwardNodeService forwardNodeService; + private final DestinationService destinationService; // Event publisher @@ -52,7 +55,8 @@ public void addForwardNode(ForwardNodeEntity forwardNodeEntity) { .filter(f -> f.getFwdAeTitle().equals(forwardNodeEntity.getFwdAeTitle())) .findFirst(); if (val.isPresent()) { - // showError("Cannot add this new node because the AE-Title already exists!"); + // showError("Cannot add this new node because the AE-Title already + // exists!"); return; } } diff --git a/src/main/java/org/karnak/backend/service/ForwardService.java b/src/main/java/org/karnak/backend/service/ForwardService.java index 1a9289946..48d5fcee0 100644 --- a/src/main/java/org/karnak/backend/service/ForwardService.java +++ b/src/main/java/org/karnak/backend/service/ForwardService.java @@ -41,6 +41,7 @@ import org.karnak.backend.dicom.WebForwardDestination; import org.karnak.backend.exception.AbortException; import org.karnak.backend.model.event.TransferMonitoringEvent; +import org.karnak.backend.model.image.TransformedPlanarImage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -207,7 +208,7 @@ public List transfer( tsuid, streamSCU.selectTransferSyntax(cuid, destination.getOutputTransferSyntax(tsuid))); List editors = destination.getDicomEditors(); - + TransformedPlanarImage transformedPlanarImage = new TransformedPlanarImage(); if (copy == null && editors.isEmpty() && syntax.getRequested().equals(tsuid)) { dataWriter = new InputStreamDataWriter(p.getData()); attributesToSend = new DicomInputStream(p.getData()).readDataset(); @@ -242,13 +243,12 @@ public List transfer( throw new AbortException( context.getAbort(), "DICOM association abort: " + context.getAbortMessage()); } - - BytesWithImageDescriptor desc = ImageAdapter.imageTranscode(attributes, syntax, context); - Editable editable = transformImage(attributes, context); - dataWriter = ImageAdapter.buildDataWriter(attributes, syntax, editable, desc); + dataWriter = buildDataWriterFromTransformedImage(syntax, context, attributes, + transformedPlanarImage); } - streamSCU.cstore(cuid, iuid, p.getPriority(), dataWriter, syntax.getSuitable()); + launchCStore(p, streamSCU, dataWriter, cuid, iuid, syntax, transformedPlanarImage); + progressNotify( destination, p.getIuid(), p.getCuid(), false, streamSCU.getNumberOfSuboperations()); monitor( @@ -303,26 +303,68 @@ public List transfer( return files; } - private static Editable transformImage( - Attributes attributes, AttributeEditorContext context) { + private void launchCStore(Params p, StoreFromStreamSCU streamSCU, DataWriter dataWriter, + String cuid, + String iuid, AdaptTransferSyntax syntax, TransformedPlanarImage transformedPlanarImage) + throws IOException, InterruptedException { + try { + streamSCU.cstore(cuid, iuid, p.getPriority(), dataWriter, syntax.getSuitable()); + } finally { + if (transformedPlanarImage != null && transformedPlanarImage.getPlanarImage() != null) { + transformedPlanarImage.getPlanarImage().release(); + } + } + } + + private DataWriter buildDataWriterFromTransformedImage(AdaptTransferSyntax syntax, + AttributeEditorContext context, + Attributes attributes, TransformedPlanarImage transformedPlanarImage) throws IOException { + DataWriter dataWriter; + BytesWithImageDescriptor desc = ImageAdapter.imageTranscode(attributes, syntax, context); + transformedPlanarImage = transformImage(attributes, context, transformedPlanarImage); + dataWriter = ImageAdapter.buildDataWriter(attributes, + syntax, + transformedPlanarImage != null ? transformedPlanarImage.getEditablePlanarImage() : null, + desc); + return dataWriter; + } + + private static TransformedPlanarImage transformImage( + Attributes attributes, AttributeEditorContext context, + TransformedPlanarImage transformedPlanarImage) { MaskArea m = context.getMaskArea(); boolean defacing = LangUtil.getEmptytoFalse(context.getProperties().getProperty(Defacer.APPLY_DEFACING)); if (m != null || defacing) { - return img -> { - PlanarImage image = img; - if (defacing) { - image = Defacer.apply(attributes, image); - } - if (m != null) { - image = MaskArea.drawShape(image.toMat(), m); - } - return image; - }; + Editable editablePlanarImage = buildEditablePlanarImage(attributes, m, defacing, + transformedPlanarImage); + transformedPlanarImage.setEditablePlanarImage(editablePlanarImage); + return transformedPlanarImage; } return null; } + private static Editable buildEditablePlanarImage(Attributes attributes, MaskArea m, + boolean defacing, TransformedPlanarImage transformedPlanarImage) { + return img -> { + PlanarImage planarImage = buildPlanarImage(attributes, m, defacing, img); + transformedPlanarImage.setPlanarImage(planarImage); + return planarImage; + }; + } + + private static PlanarImage buildPlanarImage(Attributes attributes, MaskArea m, boolean defacing, + PlanarImage img) { + PlanarImage image = img; + if (defacing) { + image = Defacer.apply(attributes, image); + } + if (m != null) { + image = MaskArea.drawShape(image.toMat(), m); + } + return image; + } + private static List cleanOrGetBulkDataFiles(DicomInputStream in, boolean clean) { FileUtil.safeClose(in); if (clean) { @@ -355,6 +397,7 @@ public void transferOther( tsuid, streamSCU.selectTransferSyntax(cuid, destination.getOutputTransferSyntax(tsuid))); List editors = destination.getDicomEditors(); + TransformedPlanarImage transformedPlanarImage = new TransformedPlanarImage(); if (editors.isEmpty() && syntax.getRequested().equals(tsuid)) { dataWriter = new DataWriterAdapter(copy); attributesOriginal.addAll(copy); @@ -377,13 +420,12 @@ public void transferOther( throw new AbortException( context.getAbort(), "DICOM association abort. " + context.getAbortMessage()); } - - BytesWithImageDescriptor desc = ImageAdapter.imageTranscode(attributes, syntax, context); - Editable editable = transformImage(attributes, context); - dataWriter = ImageAdapter.buildDataWriter(attributes, syntax, editable, desc); + dataWriter = buildDataWriterFromTransformedImage(syntax, context, attributes, + transformedPlanarImage); } - streamSCU.cstore(cuid, iuid, p.getPriority(), dataWriter, syntax.getSuitable()); + launchCStore(p, streamSCU, dataWriter, cuid, iuid, syntax, transformedPlanarImage); + progressNotify( destination, p.getIuid(), p.getCuid(), false, streamSCU.getNumberOfSuboperations()); monitor( @@ -489,8 +531,7 @@ public List transfer( if (desc == null) { stow.uploadDicom(attributes, syntax.getOriginal()); } else { - Editable editable = transformImage(attributes, context); - stow.uploadPayload(ImageAdapter.preparePlayload(attributes, syntax, desc, editable)); + uploadPayLoadFromTransformedImage(stow, syntax, context, attributes, desc); } } progressNotify(destination, p.getIuid(), p.getCuid(), false, 0); @@ -534,6 +575,21 @@ public List transfer( return files; } + private void uploadPayLoadFromTransformedImage(DicomStowRS stow, AdaptTransferSyntax syntax, + AttributeEditorContext context, Attributes attributes, BytesWithImageDescriptor desc) + throws Exception { + TransformedPlanarImage transformedPlanarImage = new TransformedPlanarImage(); + try { + transformedPlanarImage = transformImage(attributes, context, transformedPlanarImage); + stow.uploadPayload(ImageAdapter.preparePlayload(attributes, syntax, desc, + transformedPlanarImage != null ? transformedPlanarImage.getEditablePlanarImage() : null)); + } finally { + if (transformedPlanarImage != null && transformedPlanarImage.getPlanarImage() != null) { + transformedPlanarImage.getPlanarImage().release(); + } + } + } + public void transferOther( ForwardDicomNode fwdNode, WebForwardDestination destination, Attributes copy, Params p) throws IOException { @@ -566,8 +622,7 @@ public void transferOther( if (desc == null) { stow.uploadDicom(attributes, syntax.getOriginal()); } else { - Editable editable = transformImage(attributes, context); - stow.uploadPayload(ImageAdapter.preparePlayload(attributes, syntax, desc, editable)); + uploadPayLoadFromTransformedImage(stow, syntax, context, attributes, desc); } progressNotify(destination, p.getIuid(), p.getCuid(), false, 0); monitor( @@ -652,12 +707,12 @@ public static String selectTransferSyntax(Association as, String cuid, String fi /** * Publish an event for monitoring purpose * - * @param forwardNodeId ForwardNode Id - * @param destinationId Destination Id + * @param forwardNodeId ForwardNode Id + * @param destinationId Destination Id * @param attributesOriginal Original value - * @param attributesToSend De-identify value - * @param sent Flag to know if the transfer occurred - * @param reason Reason of not transferring the file + * @param attributesToSend De-identify value + * @param sent Flag to know if the transfer occurred + * @param reason Reason of not transferring the file */ private void monitor( Long forwardNodeId, diff --git a/src/main/java/org/karnak/backend/service/KheopsAlbumsService.java b/src/main/java/org/karnak/backend/service/KheopsAlbumsService.java index 4c83836de..592b54693 100644 --- a/src/main/java/org/karnak/backend/service/KheopsAlbumsService.java +++ b/src/main/java/org/karnak/backend/service/KheopsAlbumsService.java @@ -62,7 +62,7 @@ private void deleteDiffCurrentAndDatabase( if (destinationEntity.getKheopsAlbumEntities() != null && kheopsAlbumsEntityListDatabase != null && destinationEntity.getKheopsAlbumEntities().size() - != kheopsAlbumsEntityListDatabase.size()) { + != kheopsAlbumsEntityListDatabase.size()) { for (KheopsAlbumsEntity kheopsAlbumDatabase : kheopsAlbumsEntityListDatabase) { Predicate idIsAlwaysPresent = kheopsAlbum -> kheopsAlbum.getId().equals(kheopsAlbumDatabase.getId()); diff --git a/src/main/java/org/karnak/backend/service/HazelcastService.java b/src/main/java/org/karnak/backend/service/LogCacheService.java similarity index 59% rename from src/main/java/org/karnak/backend/service/HazelcastService.java rename to src/main/java/org/karnak/backend/service/LogCacheService.java index d35fa6d43..6c7f08478 100644 --- a/src/main/java/org/karnak/backend/service/HazelcastService.java +++ b/src/main/java/org/karnak/backend/service/LogCacheService.java @@ -10,24 +10,34 @@ package org.karnak.backend.service; import java.util.stream.Collectors; +import org.karnak.backend.cache.ExternalIDCache; import org.karnak.backend.config.AppConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @Service -public class HazelcastService { +public class LogCacheService { - private static final Logger LOGGER = LoggerFactory.getLogger(HazelcastService.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LogCacheService.class); - /** Log every minutes */ - // @Scheduled(fixedRate = 60000) - public void logHazelcast() { + private ExternalIDCache externalIDCache; + + public LogCacheService(ExternalIDCache externalIDCache) { + this.externalIDCache = externalIDCache; + } + + /** + * Log every minutes + */ + @Scheduled(fixedRate = 60000) + public void logCache() { LOGGER.info( String.format( - "Hazelcast values for instance %s:%s", + "Cache values for instance %s:%s", AppConfig.getInstance().getNameInstance(), - AppConfig.getInstance().getExternalIDCache().getAll().stream() + externalIDCache.getAll().stream() .map(Object::toString) .collect(Collectors.joining("***")))); } diff --git a/src/main/java/org/karnak/backend/service/NotificationService.java b/src/main/java/org/karnak/backend/service/NotificationService.java index 5f09079d1..c8c214704 100644 --- a/src/main/java/org/karnak/backend/service/NotificationService.java +++ b/src/main/java/org/karnak/backend/service/NotificationService.java @@ -39,7 +39,9 @@ import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; -/** Handle notifications */ +/** + * Handle notifications + */ @Service public class NotificationService { @@ -47,10 +49,12 @@ public class NotificationService { // Services private final TemplateEngine templateEngine; + private final JavaMailSender javaMailSender; // Repositories private final TransferStatusRepo transferStatusRepo; + private final DestinationRepo destinationRepo; @Autowired @@ -94,10 +98,12 @@ List buildNotificationsToSend() { // Update destination last check date destinationEntity.setEmailLastCheck(LocalDateTime.now(ZoneId.of("CET"))); destinationRepo.save(destinationEntity); - // Retrieve all TransferStatusEntities for this destination after the last email check + // Retrieve all TransferStatusEntities for this destination after the + // last email check List transferStatusEntitiesDestinationsLastCheck = retrieveTransferStatusDestinationLastCheck(destinationEntity, previousCheck); - // Gather TransferStatus by Source and Study: >> + // Gather TransferStatus by Source and Study: >> Map>> transferStatusBySourceAndStudy = gatherTransferStatusBySourceAndStudy(transferStatusEntitiesDestinationsLastCheck); // Build the notifications to send @@ -111,8 +117,8 @@ List buildNotificationsToSend() { * Build transfer notifications to send. * * @param transferMonitoringNotifications List of notifications to fill - * @param transferStatusBySourceAndStudy Map of TransferStatus by Source and Study:
- * >> + * @param transferStatusBySourceAndStudy Map of TransferStatus by Source and Study:
>> */ private void buildTransferMonitoringNotifications( List transferMonitoringNotifications, @@ -189,10 +195,10 @@ private TransferMonitoringNotification buildTransferMonitoringNotification( /** * Set values in transferMonitoringNotification built * - * @param transferMonitoringNotification TransferMonitoringNotification built - * @param transferStatusEntity Transfer status + * @param transferMonitoringNotification TransferMonitoringNotification built + * @param transferStatusEntity Transfer status * @param hasAtLeastOneFileNotTransferred Has at least one file not transferred - * @param useOriginalValues Flag to know if we should use original values + * @param useOriginalValues Flag to know if we should use original values */ private void buildTransferMonitoringNotificationSetValues( TransferMonitoringNotification transferMonitoringNotification, @@ -227,8 +233,8 @@ private void buildTransferMonitoringNotificationSetValues( transferStatusEntity.getForwardNodeEntity().getFwdAeTitle()); transferMonitoringNotification.setDestination( Objects.equals( - transferStatusEntity.getDestinationEntity().getDestinationType(), - DestinationType.dicom) + transferStatusEntity.getDestinationEntity().getDestinationType(), + DestinationType.dicom) ? transferStatusEntity.getDestinationEntity().toStringDicomNotificationDestination() : transferStatusEntity.getDestinationEntity().getUrl()); transferMonitoringNotification.setSubject( @@ -239,9 +245,9 @@ private void buildTransferMonitoringNotificationSetValues( * Build notification subject email * * @param hasAtLeastOneFileNotTransferred Flag to know if there is at least one file not - * transferred - * @param useOriginalValues Check if we should use original or de-identified values - * @param transferStatusEntity TransferStatusEntity to evaluate + * transferred + * @param useOriginalValues Check if we should use original or de-identified values + * @param transferStatusEntity TransferStatusEntity to evaluate * @return Subject built */ private String buildSubject( @@ -263,7 +269,7 @@ private String buildSubject( /** * Build list of values to add to the subject * - * @param useOriginalValues Flag to know if we should use original or de-identified values + * @param useOriginalValues Flag to know if we should use original or de-identified values * @param transferStatusEntity TransferStatusEntity to evaluate * @return List of values to add to the subject */ @@ -271,11 +277,12 @@ private Object[] buildSubjectValues( boolean useOriginalValues, TransferStatusEntity transferStatusEntity) { List subjectValues = new ArrayList<>(); - // Determine the values to add to the subject depending on the params set in the destination + // Determine the values to add to the subject depending on the params set in the + // destination String[] notifyObjectValues = (transferStatusEntity.getDestinationEntity().getNotifyObjectValues() == null - ? Notification.DEFAULT_SUBJECT_VALUES - : transferStatusEntity.getDestinationEntity().getNotifyObjectValues()) + ? Notification.DEFAULT_SUBJECT_VALUES + : transferStatusEntity.getDestinationEntity().getNotifyObjectValues()) .split(Notification.COMMA_SEPARATOR); // Select the values to add @@ -306,8 +313,8 @@ private Object[] buildSubjectValues( subjectValues.add( useOriginalValues ? transferStatusEntity.getStudyDateOriginal() == null - ? Notification.EMPTY_STRING - : transferStatusEntity.getStudyDateOriginal().toString() + ? Notification.EMPTY_STRING + : transferStatusEntity.getStudyDateOriginal().toString() : transferStatusEntity.getStudyDateToSend() == null ? Notification.EMPTY_STRING : transferStatusEntity.getStudyDateToSend().toString()); @@ -320,8 +327,8 @@ private Object[] buildSubjectValues( * Build subject value, if null set empty string in the subject * * @param useOriginalValues Flag to know if we should use original value - * @param original Value original - * @param toSend Value transformed to send + * @param original Value original + * @param toSend Value transformed to send * @return subject value */ private String buildSubjectValue(boolean useOriginalValues, String original, String toSend) { @@ -333,7 +340,7 @@ private String buildSubjectValue(boolean useOriginalValues, String original, Str /** * Build transfer serie summary results * - * @param transferStatusEntities TransferStatus to evaluate + * @param transferStatusEntities TransferStatus to evaluate * @param isDestinationDeIdentify Flag to know if the destination should be de-identify * @return Serie summary notifications */ @@ -364,8 +371,8 @@ private List buildSeriesSummaryNotification( * Build summary notification for the serie in parameter * * @param isDestinationDeIdentify Flag to know if the destination should be de-identify - * @param transfersToEvaluate Transfers to evaluate - * @param transferStatusEntity TransferStatus containing general series values to set + * @param transfersToEvaluate Transfers to evaluate + * @param transferStatusEntity TransferStatus containing general series values to set * @return Summary notification for this serie */ private SerieSummaryNotification buildSerieSummaryNotification( @@ -420,7 +427,7 @@ private List determineUnTransferredReasons( * Determine if we have to use originals or de-identify values. If any transfer not sent or flag * deidentification for the destination is false: use originals values * - * @param hasTransferNotSent Flag to know if there are transfer not sent + * @param hasTransferNotSent Flag to know if there are transfer not sent * @param isDestinationDeIdentify Is deidentification requested for the destination * @return true if we have to use originals values, false otherwise */ @@ -448,7 +455,7 @@ private Map>> gatherTransferStatusB * Retrieve TransferStatusEntities for this destination after the last email check * * @param destinationEntity Destination to look for - * @param lastCheck Last check for this destination + * @param lastCheck Last check for this destination * @return TransferStatusEntity found */ private List retrieveTransferStatusDestinationLastCheck( @@ -461,10 +468,10 @@ private List retrieveTransferStatusDestinationLastCheck( /** * Check if notification should be sent depending on last check of notification (compare to - * notification interval of the destination and current date)
- * A transfer should not be in progress to send the notification and an extra timer of 10s is - * added for serie transfers which are not immediately sent each time (a delay is occurring - * between transfer of files in the same serie) + * notification interval of the destination and current date)
A transfer should not be in + * progress to send the notification and an extra timer of 10s is added for serie transfers which + * are not immediately sent each time (a delay is occurring between transfer of files in the same + * serie) * * @param destinationEntity Destination to evaluate * @return true if the notification can be process, false otherwise @@ -474,14 +481,14 @@ private boolean checkDestinationLastVerification(DestinationEntity destinationEn && destinationEntity.getLastTransfer() != null // Add extra timer delay in order to insure transfer of serie is over && destinationEntity - .getLastTransfer() - .plusSeconds(Notification.EXTRA_TIMER_DELAY) - .isBefore(LocalDateTime.now(ZoneId.of("CET"))) + .getLastTransfer() + .plusSeconds(Notification.EXTRA_TIMER_DELAY) + .isBefore(LocalDateTime.now(ZoneId.of("CET"))) && (destinationEntity.getEmailLastCheck() == null - || destinationEntity - .getEmailLastCheck() - .plusSeconds(destinationEntity.getNotifyInterval().longValue()) - .isBefore(LocalDateTime.now(ZoneId.of("CET")))) + || destinationEntity + .getEmailLastCheck() + .plusSeconds(destinationEntity.getNotifyInterval().longValue()) + .isBefore(LocalDateTime.now(ZoneId.of("CET")))) && destinationEntity.isActivateNotification(); } diff --git a/src/main/java/org/karnak/backend/service/ProjectService.java b/src/main/java/org/karnak/backend/service/ProjectService.java index 01c15839d..13cb5923f 100644 --- a/src/main/java/org/karnak/backend/service/ProjectService.java +++ b/src/main/java/org/karnak/backend/service/ProjectService.java @@ -20,7 +20,9 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -/** Project service */ +/** + * Project service + */ @Service public class ProjectService { @@ -33,7 +35,7 @@ public class ProjectService { /** * Autowired constructor * - * @param projectRepo Project repository + * @param projectRepo Project repository * @param applicationEventPublisher Application Event Publisher */ @Autowired diff --git a/src/main/java/org/karnak/backend/service/PseudonymMappingService.java b/src/main/java/org/karnak/backend/service/PseudonymMappingService.java index f5ebdc682..7e7b8ebd5 100644 --- a/src/main/java/org/karnak/backend/service/PseudonymMappingService.java +++ b/src/main/java/org/karnak/backend/service/PseudonymMappingService.java @@ -12,7 +12,7 @@ import org.json.JSONArray; import org.json.JSONObject; import org.karnak.backend.api.PseudonymApi; -import org.karnak.backend.cache.MainzellistePatient; +import org.karnak.backend.cache.Patient; import org.karnak.backend.dicom.DateTimeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,8 +23,8 @@ public class PseudonymMappingService { private static final Logger LOGGER = LoggerFactory.getLogger(PseudonymMappingService.class); - public MainzellistePatient retrieveMainzellistePatient(final String pseudonym) { - MainzellistePatient mainzellistePatient = null; + public Patient retrieveMainzellistePatient(final String pseudonym) { + Patient mainzellistePatient = null; // Pseudonym api PseudonymApi pseudonymApi = new PseudonymApi(); @@ -47,7 +47,7 @@ public MainzellistePatient retrieveMainzellistePatient(final String pseudonym) { // Map to model if (jsonObject != null) { mainzellistePatient = - new MainzellistePatient( + new Patient( pseudonym, jsonObject.getString("patientID"), null, diff --git a/src/main/java/org/karnak/backend/service/SecretService.java b/src/main/java/org/karnak/backend/service/SecretService.java index 5ab808b1c..c3a332cc3 100644 --- a/src/main/java/org/karnak/backend/service/SecretService.java +++ b/src/main/java/org/karnak/backend/service/SecretService.java @@ -39,7 +39,7 @@ public SecretEntity save(SecretEntity secretEntity) { /** * Save in db a new active secret for the project in parameter * - * @param secretEntity Secret to save + * @param secretEntity Secret to save * @param projectEntity Project associated to the secret * @return Secret saved */ diff --git a/src/main/java/org/karnak/backend/service/StoreScpForwardService.java b/src/main/java/org/karnak/backend/service/StoreScpForwardService.java index 8863b8291..b363fbb4a 100644 --- a/src/main/java/org/karnak/backend/service/StoreScpForwardService.java +++ b/src/main/java/org/karnak/backend/service/StoreScpForwardService.java @@ -42,9 +42,13 @@ public class StoreScpForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(StoreScpForwardService.class); private final Device device = new Device("storescp"); + private final ApplicationEntity ae = new ApplicationEntity("*"); + private final Connection conn = new Connection(); + private volatile int priority; + private volatile int status = 0; private Map> destinations; @@ -59,10 +63,10 @@ public StoreScpForwardService(final CStoreSCPService cStoreSCPService) { /** * Init service * - * @param forwardParams the optional advanced parameters (proxy, authentication, connection and - * TLS) for the final destination - * @param fwdNode the calling DICOM node configuration - * @param destinationNode the final DICOM node configuration + * @param forwardParams the optional advanced parameters (proxy, authentication, connection and + * TLS) for the final destination + * @param fwdNode the calling DICOM node configuration + * @param destinationNode the final DICOM node configuration * @param attributesEditor the editor for modifying attributes on the fly (can be Null) */ public void init( diff --git a/src/main/java/org/karnak/backend/service/TransferMonitoringService.java b/src/main/java/org/karnak/backend/service/TransferMonitoringService.java index 8dda3b752..8c20b76a9 100644 --- a/src/main/java/org/karnak/backend/service/TransferMonitoringService.java +++ b/src/main/java/org/karnak/backend/service/TransferMonitoringService.java @@ -38,7 +38,9 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -/** Handle transfer monitoring */ +/** + * Handle transfer monitoring + */ @Service public class TransferMonitoringService { @@ -84,7 +86,7 @@ public void cleanTransferStatus() { /** * Retrieve transfer status depending on filter and pageable * - * @param filter Filter to evaluate + * @param filter Filter to evaluate * @param pageable Pageable to evaluate * @return Transfer status entities found */ @@ -147,7 +149,7 @@ public int countTransferStatus(TransferStatusFilter filter) { /** * Build a transfer status csv file depending on filters * - * @param filter Filters + * @param filter Filters * @param exportSettings Export settings */ public byte[] buildCsv(TransferStatusFilter filter, ExportSettings exportSettings) diff --git a/src/main/java/org/karnak/backend/service/dicom/DicomEchoService.java b/src/main/java/org/karnak/backend/service/dicom/DicomEchoService.java index 87e54ef1c..7a09571d0 100644 --- a/src/main/java/org/karnak/backend/service/dicom/DicomEchoService.java +++ b/src/main/java/org/karnak/backend/service/dicom/DicomEchoService.java @@ -24,7 +24,8 @@ public class DicomEchoService { @Autowired - public DicomEchoService() {} + public DicomEchoService() { + } public String dicomEcho(List nodes) throws InterruptedException, ExecutionException { StringBuilder result = new StringBuilder(); diff --git a/src/main/java/org/karnak/backend/service/dicom/WadoService.java b/src/main/java/org/karnak/backend/service/dicom/WadoService.java index ce86cbb6c..60e2ec41e 100644 --- a/src/main/java/org/karnak/backend/service/dicom/WadoService.java +++ b/src/main/java/org/karnak/backend/service/dicom/WadoService.java @@ -24,7 +24,8 @@ public class WadoService { @Autowired - public WadoService() {} + public WadoService() { + } public String checkWado(List nodes) throws InterruptedException, ExecutionException { StringBuilder result = new StringBuilder(); diff --git a/src/main/java/org/karnak/backend/service/gateway/GatewayService.java b/src/main/java/org/karnak/backend/service/gateway/GatewayService.java index 62cbd9dd6..ea5a84934 100644 --- a/src/main/java/org/karnak/backend/service/gateway/GatewayService.java +++ b/src/main/java/org/karnak/backend/service/gateway/GatewayService.java @@ -36,6 +36,7 @@ public class GatewayService implements ApplicationListener> destMap = new HashMap<>(); @@ -71,15 +75,21 @@ public class GatewaySetUpService { private final Path storePath; private final String listenerAET; + private final int listenerPort; + private final Boolean listenerTLS; + private final int intervalCheck; private final String archiveUrl; private final String clientKey; + private final String clientKeyPwd; + private final String truststorePwd; + private final String truststore; // Version gateway setup for this instance @@ -95,22 +105,26 @@ public GatewaySetUpService( this.versionRepo = versionRepo; this.destinationRepo = destinationRepo; - String path = - SystemPropertyUtil.retrieveSystemProperty( - "GATEWAY_ARCHIVE_PATH", null); // Only Archive and Pull mode + String path = SystemPropertyUtil.retrieveSystemProperty("GATEWAY_ARCHIVE_PATH", null); // Only + // Archive + // and + // Pull + // mode storePath = StringUtil.hasText(path) ? Path.of(path) : null; intervalCheck = StringUtil.getInt( - SystemPropertyUtil.retrieveSystemProperty( - "GATEWAY_PULL_CHECK_INTERNAL", "5")); // Only Pull mode - archiveUrl = - SystemPropertyUtil.retrieveSystemProperty("GATEWAY_ARCHIVE_URL", ""); // Only Archive mode + SystemPropertyUtil.retrieveSystemProperty("GATEWAY_PULL_CHECK_INTERNAL", "5")); // Only + // Pull + // mode + archiveUrl = SystemPropertyUtil.retrieveSystemProperty("GATEWAY_ARCHIVE_URL", ""); // Only + // Archive + // mode listenerAET = SystemPropertyUtil.retrieveSystemProperty("DICOM_LISTENER_AET", "KARNAK-GATEWAY"); listenerPort = 11119; listenerTLS = LangUtil.getEmptytoFalse( - SystemPropertyUtil.retrieveSystemProperty("DICOM_LISTENER_TLS", null)); + SystemPropertyUtil.retrieveSystemProperty("DICOM_LISTENER_TLS", "false")); clientKey = SystemPropertyUtil.retrieveSystemProperty("TLS_KEYSTORE_PATH", null); clientKeyPwd = SystemPropertyUtil.retrieveSystemProperty("TLS_KEYSTORE_SECRET", null); @@ -243,40 +257,17 @@ public Set getKeys() { private void addDestinationNode( List dstList, ForwardDicomNode fwdSrcNode, DestinationEntity dstNode) { try { - List editors = new ArrayList<>(); - - if (!dstNode.getCondition().isEmpty()) { - editors.add(new ConditionEditor(dstNode.getCondition())); - } - - final boolean filterBySOPClassesEnable = dstNode.isFilterBySOPClasses(); - if (filterBySOPClassesEnable) { - editors.add(new FilterEditor(dstNode.getSOPClassUIDEntityFilters())); - } - final List kheopsAlbumEntities = dstNode.getKheopsAlbumEntities(); - SwitchingAlbum switchingAlbum = new SwitchingAlbum(); - if (kheopsAlbumEntities != null && !kheopsAlbumEntities.isEmpty()) { - editors.add( - (Attributes dcm, AttributeEditorContext context) -> { - kheopsAlbumEntities.forEach( - kheopsAlbums -> { - switchingAlbum.apply(dstNode, kheopsAlbums, dcm); - }); - }); - } - - StreamRegistryEditor streamRegistryEditor = new StreamRegistryEditor(); - editors.add(streamRegistryEditor); - - boolean deidentificationEnable = dstNode.isDesidentification(); - boolean profileDefined = - dstNode.getProjectEntity() != null - && dstNode.getProjectEntity().getProfileEntity() != null; - if (deidentificationEnable && profileDefined) { // TODO add an option in destination model - editors.add(new DeIdentifyEditor(dstNode)); - } + // Apply editors + List editors = new ArrayList<>(); + applyConditionEditor(dstNode, editors); + applyFilterEditor(dstNode, editors); + SwitchingAlbum switchingAlbum = + applySwitchingAlbumEditor(dstNode, editors, kheopsAlbumEntities); + applyStreamRegistryEditor(editors); + applyDeIdentifyEditor(dstNode, editors); + applyTagMorphingEditor(dstNode, editors); DicomProgress progress = new DicomProgress(); @@ -308,9 +299,7 @@ private void addDestinationNode( (DicomProgress dicomProgress) -> { Attributes dcm = dicomProgress.getAttributes(); kheopsAlbumEntities.forEach( - kheopsAlbums -> { - switchingAlbum.applyAfterTransfer(kheopsAlbums, dcm); - }); + kheopsAlbums -> switchingAlbum.applyAfterTransfer(kheopsAlbums, dcm)); }); } dstList.add(fwd); @@ -337,6 +326,105 @@ private void addDestinationNode( } } + /** + * Apply switching album editor + * + * @param dstNode Destination + * @param editors List of editors + * @param kheopsAlbumEntities kheopsAlbumEntities + * @return SwitchingAlbum created + */ + private SwitchingAlbum applySwitchingAlbumEditor( + DestinationEntity dstNode, + List editors, + List kheopsAlbumEntities) { + SwitchingAlbum switchingAlbum = new SwitchingAlbum(); + if (kheopsAlbumEntities != null && !kheopsAlbumEntities.isEmpty()) { + editors.add(switchingEditor(dstNode, kheopsAlbumEntities, switchingAlbum)); + } + return switchingAlbum; + } + + /** + * Switching editor + * + * @param dstNode Destination + * @param kheopsAlbumEntities kheopsAlbum Entities + * @param switchingAlbum switchingAlbum + * @return Editor + */ + private AttributeEditor switchingEditor( + DestinationEntity dstNode, + List kheopsAlbumEntities, + SwitchingAlbum switchingAlbum) { + return (Attributes dcm, AttributeEditorContext context) -> + kheopsAlbumEntities.forEach( + kheopsAlbums -> switchingAlbum.apply(dstNode, kheopsAlbums, dcm)); + } + + /** + * Apply StreamRegistryEditor + * + * @param editors List of editors + */ + private void applyStreamRegistryEditor(List editors) { + editors.add(new StreamRegistryEditor()); + } + + /** + * Apply Filter editor + * + * @param dstNode Destination + * @param editors List of editors + */ + private void applyFilterEditor(DestinationEntity dstNode, List editors) { + final boolean filterBySOPClassesEnable = dstNode.isFilterBySOPClasses(); + if (filterBySOPClassesEnable) { + editors.add(new FilterEditor(dstNode.getSOPClassUIDEntityFilters())); + } + } + + /** + * Apply Condition editor + * + * @param dstNode Destination + * @param editors List of editors + */ + private void applyConditionEditor(DestinationEntity dstNode, List editors) { + if (!dstNode.getCondition().isEmpty()) { + editors.add(new ConditionEditor(dstNode.getCondition())); + } + } + + /** + * Depending on the destination, apply changes on tags: deidentification or the tag morphing + * profiles + * + * @param dstNode Destination + * @param editors List of editors + */ + private void applyDeIdentifyEditor(DestinationEntity dstNode, List editors) { + if (dstNode.getDeIdentificationProjectEntity() != null + && dstNode.getDeIdentificationProjectEntity().getProfileEntity() != null + && dstNode.isDesidentification()) { + editors.add(new DeIdentifyEditor(dstNode)); + } + } + + /** + * Depending on the destination, apply changes on tags: the tag morphing profiles + * + * @param dstNode Destination + * @param editors List of editors + */ + private void applyTagMorphingEditor(DestinationEntity dstNode, List editors) { + if (dstNode.getTagMorphingProjectEntity() != null + && dstNode.getTagMorphingProjectEntity().getProfileEntity() != null + && dstNode.isActivateTagMorphing()) { + editors.add(new TagMorphingEditor(dstNode)); + } + } + public void reloadGatewayPersistence() { List list = new ArrayList<>(forwardNodeRepo.findAll()); @@ -445,13 +533,16 @@ public void refreshVersionGatewaySetUp() { gatewaySetUpVersion = lastVersion.getGatewaySetup(); } - /** Check if a refresh of the configuration should be done */ + /** + * Check if a refresh of the configuration should be done + */ @Scheduled(fixedRate = 5000) - private void checkRefreshGatewaySetUp() { + public void checkRefreshGatewaySetUp() { // Retrieve last gateway version VersionEntity lastVersion = versionRepo.findTopByOrderByIdDesc(); - // Check if refresh needed: current version of the gateway setup for this instance is lower than + // Check if refresh needed: current version of the gateway setup for this instance + // is lower than // the last version in DB if (lastVersion != null && gatewaySetUpVersion < lastVersion.getGatewaySetup()) { // Check no transfer is in progress diff --git a/src/main/java/org/karnak/backend/service/kheops/SwitchingAlbum.java b/src/main/java/org/karnak/backend/service/kheops/SwitchingAlbum.java index c6cbf7b1c..c915843be 100644 --- a/src/main/java/org/karnak/backend/service/kheops/SwitchingAlbum.java +++ b/src/main/java/org/karnak/backend/service/kheops/SwitchingAlbum.java @@ -38,9 +38,13 @@ public class SwitchingAlbum { public static final ImmutableList MIN_SCOPE_SOURCE = ImmutableList.of("read", "send"); + public static final ImmutableList MIN_SCOPE_DESTINATION = ImmutableList.of("write"); + private static final Logger LOGGER = LoggerFactory.getLogger(SwitchingAlbum.class); + private final KheopsApi kheopsAPI; + private final Map switchingAlbumToDo = new WeakHashMap<>(); public SwitchingAlbum() { @@ -49,7 +53,7 @@ public SwitchingAlbum() { private static HMAC generateHMAC(DestinationEntity destinationEntity) { if (destinationEntity.isDesidentification()) { - ProjectEntity projectEntity = destinationEntity.getProjectEntity(); + ProjectEntity projectEntity = destinationEntity.getDeIdentificationProjectEntity(); SecretEntity secretEntity = projectEntity.retrieveActiveSecret(); return secretEntity != null ? new HMAC(secretEntity.getKey()) : null; } @@ -58,11 +62,11 @@ private static HMAC generateHMAC(DestinationEntity destinationEntity) { private static String hashUIDonDeidentification( DestinationEntity destinationEntity, String inputUID, HMAC hmac, int tag) { - ActionItem action = getAction(destinationEntity, tag); - if (destinationEntity.isDesidentification() && hmac != null && action instanceof UID) { - return hmac.uidHash(inputUID); - } - return inputUID; + return destinationEntity.isDesidentification() + && hmac != null + && getAction(destinationEntity, tag) instanceof UID + ? hmac.uidHash(inputUID) + : inputUID; } private static boolean validateCondition(String condition, Attributes dcm) { @@ -84,10 +88,11 @@ public static boolean validateIntrospectedToken( } public static ActionItem getAction(DestinationEntity destinationEntity, int tag) { - if (destinationEntity.getProjectEntity() != null - && destinationEntity.getProjectEntity().getProfileEntity() != null) { + if (destinationEntity.getDeIdentificationProjectEntity() != null + && destinationEntity.getDeIdentificationProjectEntity().getProfileEntity() != null) { List profileItems = - Profile.getProfileItems(destinationEntity.getProjectEntity().getProfileEntity()); + Profile.getProfileItems( + destinationEntity.getDeIdentificationProjectEntity().getProfileEntity()); for (ProfileItem profileItem : profileItems.stream() .filter(p -> !(p instanceof CleanPixelData)) @@ -133,9 +138,9 @@ public void apply( if ((condition == null || condition.length() == 0 || validateCondition(condition, dcm)) && metadataToDo.stream() - .noneMatch( - metadataSwitching -> - metadataSwitching.getSeriesInstanceUID().equals(seriesInstanceUID))) { + .noneMatch( + metadataSwitching -> + metadataSwitching.getSeriesInstanceUID().equals(seriesInstanceUID))) { final boolean validAuthorizationSource = validateToken(MIN_SCOPE_SOURCE, urlAPI, authorizationSource); final boolean validDestinationSource = diff --git a/src/main/java/org/karnak/backend/service/profilepipe/AttributesByDefault.java b/src/main/java/org/karnak/backend/service/profilepipe/AttributesByDefault.java index eee0fdfee..ff48eed4d 100644 --- a/src/main/java/org/karnak/backend/service/profilepipe/AttributesByDefault.java +++ b/src/main/java/org/karnak/backend/service/profilepipe/AttributesByDefault.java @@ -28,7 +28,8 @@ public class AttributesByDefault { - private AttributesByDefault() {} + private AttributesByDefault() { + } public static void setDeidentificationMethodCodeSequence( Attributes dcm, ProjectEntity projectEntity) { diff --git a/src/main/java/org/karnak/backend/service/profilepipe/Profile.java b/src/main/java/org/karnak/backend/service/profilepipe/Profile.java index a22c9e7c7..c0ed2dc38 100644 --- a/src/main/java/org/karnak/backend/service/profilepipe/Profile.java +++ b/src/main/java/org/karnak/backend/service/profilepipe/Profile.java @@ -62,7 +62,9 @@ public class Profile { private static final Logger LOGGER = LoggerFactory.getLogger(Profile.class); private final List profiles; + private final Pseudonym pseudonym; + private final Map maskMap; public Profile(ProfileEntity profileEntity) { @@ -155,8 +157,8 @@ public void applyAction( if (profileEntity.getCondition() == null || profileEntity.getCodeName().equals(ProfileItemType.DEFACING.getClassAlias()) || profileEntity - .getCodeName() - .equals(ProfileItemType.CLEAN_PIXEL_DATA.getClassAlias())) { + .getCodeName() + .equals(ProfileItemType.CLEAN_PIXEL_DATA.getClassAlias())) { currentAction = profileEntity.getAction(dcm, dcmCopy, tag, hmac); } else { boolean conditionIsOk = @@ -216,7 +218,8 @@ public void applyCleanPixelData( } String scuPattern = sopClassUID + "."; MaskArea mask = getMask(dcmCopy.getString(Tag.StationName)); - // A mask must be applied with all the US and Secondary Capture sopClassUID, and with + // A mask must be applied with all the US and Secondary Capture sopClassUID, + // and with // BurnedInAnnotation if (isCleanPixelAllowedDependingImageType(dcmCopy, sopClassUID, scuPattern) && evaluateConditionCleanPixelData(dcmCopy)) { @@ -234,14 +237,15 @@ && evaluateConditionCleanPixelData(dcmCopy)) { /** * Determine if the clean pixel should be applied depending on the image type * - * @param dcmCopy Attributes + * @param dcmCopy Attributes * @param sopClassUID SopClassUID - * @param scuPattern Pattern + * @param scuPattern Pattern * @return true if the clean pixel could be applied */ private boolean isCleanPixelAllowedDependingImageType( Attributes dcmCopy, String sopClassUID, String scuPattern) { - // A mask must be applied with all the US and Secondary Capture sopClassUID, and with + // A mask must be applied with all the US and Secondary Capture sopClassUID, and + // with // BurnedInAnnotation return scuPattern.startsWith("1.2.840.10008.5.1.4.1.1.6.") || scuPattern.startsWith("1.2.840.10008.5.1.4.1.1.7.") @@ -293,16 +297,26 @@ public void applyDefacing(Attributes dcmCopy, AttributeEditorContext context) { } } - public void apply( + /** + * Apply deidentification + * + * @param dcm Attributes + * @param destinationEntity Destination + * @param profileEntity Profile + * @param context Context + * @param projectEntity Project + */ + public void applyDeIdentification( Attributes dcm, DestinationEntity destinationEntity, ProfileEntity profileEntity, - AttributeEditorContext context) { + AttributeEditorContext context, + ProjectEntity projectEntity) { final String SOPInstanceUID = dcm.getString(Tag.SOPInstanceUID); final String SeriesInstanceUID = dcm.getString(Tag.SeriesInstanceUID); final String IssuerOfPatientID = dcm.getString(Tag.IssuerOfPatientID); final String PatientID = dcm.getString(Tag.PatientID); - final HMAC hmac = generateHMAC(destinationEntity, PatientID); + final HMAC hmac = generateHMAC(PatientID, projectEntity); MDC.put("SOPInstanceUID", SOPInstanceUID); MDC.put("SeriesInstanceUID", SeriesInstanceUID); @@ -328,23 +342,57 @@ public void apply( // Set tags by default AttributesByDefault.setPatientModule( - dcm, newPatientID, pseudonymValue, destinationEntity.getProjectEntity()); + dcm, newPatientID, pseudonymValue, destinationEntity.getDeIdentificationProjectEntity()); AttributesByDefault.setSOPCommonModule(dcm); AttributesByDefault.setClinicalTrialAttributes( - dcm, destinationEntity.getProjectEntity(), pseudonymValue); + dcm, destinationEntity.getDeIdentificationProjectEntity(), pseudonymValue); final Marker clincalMarker = MarkerFactory.getMarker("CLINICAL"); MDC.put("DeidentifySOPInstanceUID", dcm.getString(Tag.SOPInstanceUID)); MDC.put("DeidentifySeriesInstanceUID", dcm.getString(Tag.SeriesInstanceUID)); - MDC.put("ProjectName", destinationEntity.getProjectEntity().getName()); + MDC.put("ProjectName", destinationEntity.getDeIdentificationProjectEntity().getName()); + MDC.put("ProfileName", profileEntity.getName()); + MDC.put("ProfileCodenames", profilesCodeName); + LOGGER.info(clincalMarker, ""); + MDC.clear(); + } + + public void applyTagMorphing( + Attributes dcm, + DestinationEntity destinationEntity, + ProfileEntity profileEntity, + AttributeEditorContext context, + ProjectEntity projectEntity) { + final String SOPInstanceUID = dcm.getString(Tag.SOPInstanceUID); + final String SeriesInstanceUID = dcm.getString(Tag.SeriesInstanceUID); + final String IssuerOfPatientID = dcm.getString(Tag.IssuerOfPatientID); + final String PatientID = dcm.getString(Tag.PatientID); + final HMAC hmac = generateHMAC(PatientID, projectEntity); + + MDC.put("SOPInstanceUID", SOPInstanceUID); + MDC.put("SeriesInstanceUID", SeriesInstanceUID); + MDC.put("issuerOfPatientID", IssuerOfPatientID); + MDC.put("PatientID", PatientID); + + String profilesCodeName = + profiles.stream().map(ProfileItem::getCodeName).collect(Collectors.joining("-")); + + Attributes dcmCopy = new Attributes(dcm); + + // Apply actions on tags + applyAction(dcm, dcmCopy, hmac, null, null, context); + + final Marker clincalMarker = MarkerFactory.getMarker("CLINICAL"); + MDC.put("TagMorphingSOPInstanceUID", dcm.getString(Tag.SOPInstanceUID)); + MDC.put("TagMorphingSeriesInstanceUID", dcm.getString(Tag.SeriesInstanceUID)); + MDC.put("ProjectName", destinationEntity.getTagMorphingProjectEntity().getName()); MDC.put("ProfileName", profileEntity.getName()); MDC.put("ProfileCodenames", profilesCodeName); LOGGER.info(clincalMarker, ""); MDC.clear(); } - private HMAC generateHMAC(DestinationEntity destinationEntity, String patientID) { - ProjectEntity projectEntity = destinationEntity.getProjectEntity(); + private HMAC generateHMAC(String patientID, ProjectEntity projectEntity) { if (projectEntity == null) { throw new IllegalStateException( "Cannot build the HMAC a project is not associate at the destination"); diff --git a/src/main/java/org/karnak/backend/service/profilepipe/Pseudonym.java b/src/main/java/org/karnak/backend/service/profilepipe/Pseudonym.java index ac2ca944e..320b9afb6 100644 --- a/src/main/java/org/karnak/backend/service/profilepipe/Pseudonym.java +++ b/src/main/java/org/karnak/backend/service/profilepipe/Pseudonym.java @@ -12,7 +12,7 @@ import org.dcm4che3.data.Attributes; import org.dcm4che3.util.TagUtils; import org.karnak.backend.api.PseudonymApi; -import org.karnak.backend.cache.MainzellistePatient; +import org.karnak.backend.cache.Patient; import org.karnak.backend.cache.PatientClient; import org.karnak.backend.config.AppConfig; import org.karnak.backend.data.entity.DestinationEntity; @@ -28,6 +28,7 @@ public class Pseudonym { private static final Logger LOGGER = LoggerFactory.getLogger(Pseudonym.class); private final PatientClient externalIdCache; + private final PatientClient mainzellisteCache; public Pseudonym() { @@ -46,7 +47,8 @@ public String generatePseudonym(DestinationEntity destinationEntity, Attributes } if (destinationEntity.getPseudonymType().equals(PseudonymType.CACHE_EXTID)) { - return getCacheExtid(patientMetadata, destinationEntity.getProjectEntity().getId()); + return getCacheExtid( + patientMetadata, destinationEntity.getDeIdentificationProjectEntity().getId()); } if (destinationEntity.getPseudonymType().equals(PseudonymType.EXTID_IN_TAG)) { @@ -137,8 +139,8 @@ public String getMainzellisteExtID(PatientMetadata patientMetadata) { } private void cachingMainzellistePseudonym(String pseudonym, PatientMetadata patientMetadata) { - final MainzellistePatient mainzellistePatient = - new MainzellistePatient( + final Patient mainzellistePatient = + new Patient( pseudonym, patientMetadata.getPatientID(), patientMetadata.getPatientFirstName(), diff --git a/src/main/java/org/karnak/backend/service/thread/DicomEchoThread.java b/src/main/java/org/karnak/backend/service/thread/DicomEchoThread.java index 789b54152..c7050da63 100644 --- a/src/main/java/org/karnak/backend/service/thread/DicomEchoThread.java +++ b/src/main/java/org/karnak/backend/service/thread/DicomEchoThread.java @@ -29,7 +29,7 @@ public String call() throws Exception { result.append("

"); DicomNode dcmNode = node.getCalledNode(); result.append("

DICOM Echo: "); - result.append(node.toString()); + result.append(node); result.append("
"); result.append(dcmNode.toString()); result.append("
"); diff --git a/src/main/java/org/karnak/backend/util/Counter.java b/src/main/java/org/karnak/backend/util/Counter.java index 5972fa6b1..8c9134ab9 100644 --- a/src/main/java/org/karnak/backend/util/Counter.java +++ b/src/main/java/org/karnak/backend/util/Counter.java @@ -14,6 +14,7 @@ public class Counter { private final AtomicInteger count = new AtomicInteger(0); + private final int interval; public Counter(int interval) { diff --git a/src/main/java/org/karnak/backend/util/DateFormat.java b/src/main/java/org/karnak/backend/util/DateFormat.java index 5438d5fd0..bf7af393f 100644 --- a/src/main/java/org/karnak/backend/util/DateFormat.java +++ b/src/main/java/org/karnak/backend/util/DateFormat.java @@ -27,13 +27,17 @@ import org.slf4j.LoggerFactory; public class DateFormat { + private static final Logger LOGGER = LoggerFactory.getLogger(DateFormat.class); // Date formats public static final String FORMAT_DDMMYYYY_SLASH = "dd/MM/yyyy"; + public static final String FORMAT_DDMMYYYY_SLASH_HHMMSS_2POINTS = "dd/MM/yyyy HH:mm:ss"; + public static final String FORMAT_DDMMYYYY_SLASH_HHMMSS_2POINTS_SSS_POINT = "dd/MM/yyyy HH:mm:ss.SSS"; + public static final String FORMAT_DDMMYYYY_SLASH_HHMMSS_2POINTS_SSSSSS_POINT = "dd/MM/yyyy HH:mm:ss.SSSSSS"; @@ -53,7 +57,7 @@ public static DateTimeFormatter dateTimeFormatter(final String format) { /** * Format a LocalDate to a specifig * - * @param date Date to format + * @param date Date to format * @param format Format to apply * @return Formatted date String */ @@ -65,7 +69,7 @@ public static String format(final LocalDate date, final String format) { * Format a LocalDateTime to a specific format * * @param dateTime Date to format - * @param format Format to apply + * @param format Format to apply * @return Formatted date String */ public static String format(final LocalDateTime dateTime, final String format) { diff --git a/src/main/java/org/karnak/backend/util/MetadataDICOMObject.java b/src/main/java/org/karnak/backend/util/MetadataDICOMObject.java index bcc1e7e93..f874af019 100644 --- a/src/main/java/org/karnak/backend/util/MetadataDICOMObject.java +++ b/src/main/java/org/karnak/backend/util/MetadataDICOMObject.java @@ -15,9 +15,9 @@ public class MetadataDICOMObject { /* - * Search a tagValue in the current DicomObject and his parent - * Will loop in the parent of the DicomObject until the last parent or the tagValue - * */ + * Search a tagValue in the current DicomObject and his parent Will loop in the parent + * of the DicomObject until the last parent or the tagValue + */ public static String getValue(Attributes dcm, int tag) { return getValueRec(dcm, tag); } @@ -32,9 +32,9 @@ private static String getValueRec(Attributes dcm, int tag) { } /* - * Generate the tag Path as needed in the class StandardDICOM - * Will loop in the parent of the DicomObject until the last parent - * */ + * Generate the tag Path as needed in the class StandardDICOM Will loop in the parent + * of the DicomObject until the last parent + */ public static String getTagPath(Attributes dcm, int currentTag) { return getTagPathRec(dcm, TagUtils.toString(currentTag)); } diff --git a/src/main/java/org/karnak/backend/util/NativeLibraryManager.java b/src/main/java/org/karnak/backend/util/NativeLibraryManager.java index c3966a1ec..67a3eff63 100644 --- a/src/main/java/org/karnak/backend/util/NativeLibraryManager.java +++ b/src/main/java/org/karnak/backend/util/NativeLibraryManager.java @@ -26,7 +26,8 @@ public class NativeLibraryManager { private static final Logger LOGGER = LoggerFactory.getLogger(NativeLibraryManager.class); - private NativeLibraryManager() {} + private NativeLibraryManager() { + } public static void initNativeLibs(URL resource) { Optional oLibPath = diff --git a/src/main/java/org/karnak/backend/util/PatientClientUtil.java b/src/main/java/org/karnak/backend/util/PatientClientUtil.java index 8b7b2a2e4..9255afe55 100644 --- a/src/main/java/org/karnak/backend/util/PatientClientUtil.java +++ b/src/main/java/org/karnak/backend/util/PatientClientUtil.java @@ -9,8 +9,8 @@ */ package org.karnak.backend.util; +import org.karnak.backend.cache.Patient; import org.karnak.backend.cache.PatientClient; -import org.karnak.backend.cache.PseudonymPatient; import org.karnak.backend.model.profilepipe.PatientMetadata; public class PatientClientUtil { @@ -38,7 +38,7 @@ public static String getPseudonym( private static String getCachedKey( String key, PatientMetadata patientMetadata, PatientClient cache) { - final PseudonymPatient patient = cache.get(key); + final Patient patient = cache.get(key); if (patient != null && patientMetadata.compareCachedPatient(patient)) { return patient.getPseudonym(); } @@ -49,7 +49,7 @@ public static String generateKey(String patientID, String issuerOfPatientID) { return patientID.concat(issuerOfPatientID == null ? "" : issuerOfPatientID); } - public static String generateKey(PseudonymPatient patient) { + public static String generateKey(Patient patient) { String patientID = patient.getPatientId(); String issuerOfPatientID = patient.getIssuerOfPatientId(); return generateKey(patientID, issuerOfPatientID); @@ -66,8 +66,8 @@ public static String generateKey(PatientMetadata patientMetadata, Long projectID return key.concat(projectID == null ? "" : projectID.toString()); } - public static String generateKey(PseudonymPatient pseudonymPatient, Long projectID) { - final String key = generateKey(pseudonymPatient); + public static String generateKey(Patient patient, Long projectID) { + final String key = generateKey(patient); return key.concat(projectID == null ? "" : projectID.toString()); } } diff --git a/src/main/java/org/karnak/backend/util/PrivateTagPattern.java b/src/main/java/org/karnak/backend/util/PrivateTagPattern.java index 0f80e8674..dbf403faf 100644 --- a/src/main/java/org/karnak/backend/util/PrivateTagPattern.java +++ b/src/main/java/org/karnak/backend/util/PrivateTagPattern.java @@ -10,5 +10,6 @@ package org.karnak.backend.util; public class PrivateTagPattern { + public static final String TAG_PATTERN = "(GGGG,EEEE) WHERE GGGG IS ODD"; } diff --git a/src/main/java/org/karnak/backend/util/SecurityUtil.java b/src/main/java/org/karnak/backend/util/SecurityUtil.java index 5698d5ab1..beea806ce 100644 --- a/src/main/java/org/karnak/backend/util/SecurityUtil.java +++ b/src/main/java/org/karnak/backend/util/SecurityUtil.java @@ -44,7 +44,7 @@ public static boolean isFrameworkInternalRequest(HttpServletRequest request) { final String parameterValue = request.getParameter(ApplicationConstants.REQUEST_TYPE_PARAMETER); return parameterValue != null && Stream.of(HandlerHelper.RequestType.values()) - .anyMatch(r -> r.getIdentifier().equals(parameterValue)); + .anyMatch(r -> r.getIdentifier().equals(parameterValue)); } /** @@ -67,7 +67,7 @@ public static boolean isUserLoggedIn() { public static boolean isUserAdmin() { return SecurityUtil.isUserLoggedIn() && SecurityContextHolder.getContext().getAuthentication().getAuthorities().stream() - .anyMatch(ga -> Objects.equals(ga.getAuthority(), SecurityRole.ADMIN_ROLE.getRole())); + .anyMatch(ga -> Objects.equals(ga.getAuthority(), SecurityRole.ADMIN_ROLE.getRole())); } /** @@ -94,14 +94,16 @@ public static boolean isAccessGranted(Class securedClass) { isAccessGranted = authentication != null && authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .anyMatch(allowedRoles::contains); + .map(GrantedAuthority::getAuthority) + .anyMatch(allowedRoles::contains); } } return isAccessGranted; } - /** Sign out method */ + /** + * Sign out method + */ public static void signOut() { try { VaadinServletService.getCurrentServletRequest().logout(); diff --git a/src/main/java/org/karnak/backend/util/ServletUtil.java b/src/main/java/org/karnak/backend/util/ServletUtil.java index 0aa9d8785..024e0b541 100644 --- a/src/main/java/org/karnak/backend/util/ServletUtil.java +++ b/src/main/java/org/karnak/backend/util/ServletUtil.java @@ -25,7 +25,8 @@ public class ServletUtil { private static final Logger LOGGER = LoggerFactory.getLogger(ServletUtil.class); - private ServletUtil() {} + private ServletUtil() { + } public static String getFirstParameter(Object val) { if (val instanceof String[]) { @@ -43,7 +44,7 @@ public static String[] getParameters(Object val) { if (val instanceof String[]) { return (String[]) val; } else if (val != null) { - return new String[] {val.toString()}; + return new String[]{val.toString()}; } return null; } @@ -55,7 +56,7 @@ public static Object addParameter(Object val, String arg) { arr[array.length] = arg; return arr; } else if (val != null) { - return new String[] {val.toString(), arg}; + return new String[]{val.toString(), arg}; } return arg; } @@ -128,9 +129,9 @@ private static void handleException(Exception e) { ignoreException = message != null && (message.indexOf("Connection reset") != -1 - || message.indexOf("Broken pipe") != -1 - || message.indexOf("Socket closed") != -1 - || message.indexOf("connection abort") != -1); + || message.indexOf("Broken pipe") != -1 + || message.indexOf("Socket closed") != -1 + || message.indexOf("connection abort") != -1); } else { ignoreException = throwable.getClass().getName().indexOf("ClientAbortException") >= 0 diff --git a/src/main/java/org/karnak/backend/util/ShiftDate.java b/src/main/java/org/karnak/backend/util/ShiftDate.java index 5ba810e78..dfb9ed6d0 100644 --- a/src/main/java/org/karnak/backend/util/ShiftDate.java +++ b/src/main/java/org/karnak/backend/util/ShiftDate.java @@ -26,9 +26,11 @@ import org.weasis.dicom.util.DateUtil; public class ShiftDate { + private static final Logger LOGGER = LoggerFactory.getLogger(ShiftDate.class); - private ShiftDate() {} + private ShiftDate() { + } public static String dateByDays(String date, int shiftDays) { LocalDate localDate = DateTimeUtils.parseDA(date); diff --git a/src/main/java/org/karnak/backend/util/ShiftRangeDate.java b/src/main/java/org/karnak/backend/util/ShiftRangeDate.java index 05f6bd8a5..dc2ec5d5f 100644 --- a/src/main/java/org/karnak/backend/util/ShiftRangeDate.java +++ b/src/main/java/org/karnak/backend/util/ShiftRangeDate.java @@ -22,7 +22,8 @@ public class ShiftRangeDate { private static final Logger LOGGER = LoggerFactory.getLogger(ShiftRangeDate.class); - private ShiftRangeDate() {} + private ShiftRangeDate() { + } public static void verifyShiftArguments(List argumentEntities) throws IllegalArgumentException { diff --git a/src/main/java/org/karnak/backend/util/SpringDocUtil.java b/src/main/java/org/karnak/backend/util/SpringDocUtil.java index 10f2c85de..0807ec205 100644 --- a/src/main/java/org/karnak/backend/util/SpringDocUtil.java +++ b/src/main/java/org/karnak/backend/util/SpringDocUtil.java @@ -10,7 +10,10 @@ package org.karnak.backend.util; public class SpringDocUtil { - /** Echo */ + + /** + * Echo + */ // Examples // Destinations (with status) public static final String EXAMPLE_VALUES_STATUS_DESTINATIONS_ECHO = diff --git a/src/main/java/org/karnak/backend/util/SystemPropertyUtil.java b/src/main/java/org/karnak/backend/util/SystemPropertyUtil.java index 69fc24af7..92f41e215 100644 --- a/src/main/java/org/karnak/backend/util/SystemPropertyUtil.java +++ b/src/main/java/org/karnak/backend/util/SystemPropertyUtil.java @@ -13,12 +13,13 @@ public class SystemPropertyUtil { - private SystemPropertyUtil() {} + private SystemPropertyUtil() { + } /** * Retrieve system property * - * @param key Key + * @param key Key * @param defaultValue default value * @return property found */ diff --git a/src/main/java/org/karnak/frontend/AppShell.java b/src/main/java/org/karnak/frontend/AppShell.java index cfeeb9e59..0a27ff145 100644 --- a/src/main/java/org/karnak/frontend/AppShell.java +++ b/src/main/java/org/karnak/frontend/AppShell.java @@ -19,4 +19,6 @@ */ @PWA(name = "Karnak Gateway", shortName = "karnak", iconPath = "icons/logo.png") @Push -public class AppShell implements AppShellConfigurator {} +public class AppShell implements AppShellConfigurator { + +} diff --git a/src/main/java/org/karnak/frontend/ErrorView.java b/src/main/java/org/karnak/frontend/ErrorView.java index 7c68f533c..a685e1598 100644 --- a/src/main/java/org/karnak/frontend/ErrorView.java +++ b/src/main/java/org/karnak/frontend/ErrorView.java @@ -19,7 +19,9 @@ import com.vaadin.flow.router.ParentLayout; import javax.servlet.http.HttpServletResponse; -/** View shown when trying to navigate to a view that does not exist using */ +/** + * View shown when trying to navigate to a view that does not exist using + */ @ParentLayout(MainLayout.class) @SuppressWarnings("serial") public class ErrorView extends VerticalLayout implements HasErrorParameter { diff --git a/src/main/java/org/karnak/frontend/MainLayout.java b/src/main/java/org/karnak/frontend/MainLayout.java index b99d23d7c..df5b50605 100644 --- a/src/main/java/org/karnak/frontend/MainLayout.java +++ b/src/main/java/org/karnak/frontend/MainLayout.java @@ -32,7 +32,9 @@ import org.karnak.frontend.pseudonym.mapping.PseudonymMappingView; import org.springframework.security.access.annotation.Secured; -/** The main layout. Contains the navigation menu. */ +/** + * The main layout. Contains the navigation menu. + */ @NpmPackage(value = "@polymer/iron-icons", version = "3.0.1") @JsModule("@polymer/iron-icons/iron-icons.js") @JsModule("@vaadin/vaadin-lumo-styles/badge.js") @@ -68,7 +70,8 @@ public MainLayout() { MonitoringView.class, MonitoringView.VIEW_NAME, new IronIcon("icons", "history")); addSecuredMenu(DicomMainView.class, DicomMainView.VIEW_NAME, new IronIcon("icons", "build")); addSecuredMenu(HelpView.class, HelpView.VIEW_NAME, new IronIcon("icons", "help")); - // menu.addView(AboutView.class, AboutView.VIEW_NAME, new IronIcon("icons", "info")); + // menu.addView(AboutView.class, AboutView.VIEW_NAME, new IronIcon("icons", + // "info")); // Add menu to the layout add(menu); @@ -85,8 +88,8 @@ protected void onAttach(AttachEvent attachEvent) { * Build and add secured menus * * @param securedClass View to secure - * @param viewName Name of the view - * @param icon Icon to apply to the menu + * @param viewName Name of the view + * @param icon Icon to apply to the menu */ private void addSecuredMenu( Class securedClass, String viewName, IronIcon icon) { diff --git a/src/main/java/org/karnak/frontend/Menu.java b/src/main/java/org/karnak/frontend/Menu.java index d9b3b6c95..47149b01d 100644 --- a/src/main/java/org/karnak/frontend/Menu.java +++ b/src/main/java/org/karnak/frontend/Menu.java @@ -33,8 +33,11 @@ public class Menu extends FlexLayout { private static final String SHOW_TABS = "show-tabs"; + private final ToggleButtonTheme toggleButtonTheme; + private Tabs tabs; + private RadioButtonGroup radioGroup; public Menu() { @@ -80,8 +83,8 @@ public Menu() { * Add a view to the navigation menu * * @param viewClass that has a {@code Route} annotation - * @param caption view caption in the menu - * @param icon view icon in the menu + * @param caption view caption in the menu + * @param icon view icon in the menu */ public void addView(Class viewClass, String caption, IronIcon icon) { Tab tab = new Tab(); diff --git a/src/main/java/org/karnak/frontend/admin/AdminView.java b/src/main/java/org/karnak/frontend/admin/AdminView.java index dce6654da..c7f5fdd08 100644 --- a/src/main/java/org/karnak/frontend/admin/AdminView.java +++ b/src/main/java/org/karnak/frontend/admin/AdminView.java @@ -13,7 +13,9 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.PageTitle; -/** Admin view that is registered dynamically on admin user login. */ +/** + * Admin view that is registered dynamically on admin user login. + */ @PageTitle("KARNAK - Admin") @SuppressWarnings("serial") public class AdminView extends VerticalLayout { diff --git a/src/main/java/org/karnak/frontend/authentication/CurrentUser.java b/src/main/java/org/karnak/frontend/authentication/CurrentUser.java index 5f822d489..b41b22811 100644 --- a/src/main/java/org/karnak/frontend/authentication/CurrentUser.java +++ b/src/main/java/org/karnak/frontend/authentication/CurrentUser.java @@ -21,11 +21,14 @@ */ public final class CurrentUser { - /** The attribute key used to store the username in the session. */ + /** + * The attribute key used to store the username in the session. + */ public static final String CURRENT_USER_SESSION_ATTRIBUTE_KEY = CurrentUser.class.getCanonicalName(); - private CurrentUser() {} + private CurrentUser() { + } /** * Returns the name of the current user stored in the current session, or an empty string if no diff --git a/src/main/java/org/karnak/frontend/authentication/LoginScreen.java b/src/main/java/org/karnak/frontend/authentication/LoginScreen.java index 7f0f79dd8..6702f23cd 100644 --- a/src/main/java/org/karnak/frontend/authentication/LoginScreen.java +++ b/src/main/java/org/karnak/frontend/authentication/LoginScreen.java @@ -32,7 +32,9 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; -/** UI content when the user is not logged in yet. */ +/** + * UI content when the user is not logged in yet. + */ @Route(LoginScreen.ROUTE) @PageTitle("KARNAK - Login") @CssImport(value = "./styles/shared-styles.css") @@ -70,7 +72,9 @@ public void beforeEnter(BeforeEnterEvent beforeEnterEvent) { } } - /** Build User Interface */ + /** + * Build User Interface + */ private void buildUI() { setSizeFull(); setClassName("login-screen"); @@ -108,7 +112,8 @@ private void buildUI() { */ private Component buildLoginMainComponent() { - // sets the LoginForm action to "login" in order to post the login form to Spring Security + // sets the LoginForm action to "login" in order to post the login form to Spring + // Security loginForm.setAction("login"); // deactivate forgot password button @@ -147,7 +152,8 @@ private void login(LoginForm.LoginEvent event) { .anyMatch(ga -> Objects.equals(ga.getAuthority(), SecurityRole.ADMIN_ROLE.getRole()))) { // if authentication was successful and user is admin, - // we will update the security context and redirect to the page requested first + // we will update the security context and redirect to the page requested + // first SecurityContextHolder.getContext().setAuthentication(authentication); UI.getCurrent().navigate(requestCache.resolveRedirectUrl()); } diff --git a/src/main/java/org/karnak/frontend/authentication/NotAuthorizedScreen.java b/src/main/java/org/karnak/frontend/authentication/NotAuthorizedScreen.java index 1ca6ee19e..363afaf12 100644 --- a/src/main/java/org/karnak/frontend/authentication/NotAuthorizedScreen.java +++ b/src/main/java/org/karnak/frontend/authentication/NotAuthorizedScreen.java @@ -25,7 +25,9 @@ import org.karnak.frontend.image.LogoKarnak; import org.springframework.beans.factory.annotation.Autowired; -/** UI content when the user is not authorized to see the view. */ +/** + * UI content when the user is not authorized to see the view. + */ @Route(NotAuthorizedScreen.ROUTE) @PageTitle("KARNAK - Not authorized") @CssImport(value = "./styles/shared-styles.css") @@ -43,7 +45,9 @@ public NotAuthorizedScreen() { buildUI(); } - /** Build User Interface */ + /** + * Build User Interface + */ private void buildUI() { setSizeFull(); setClassName("not-authorized-screen"); diff --git a/src/main/java/org/karnak/frontend/component/AbstractDialog.java b/src/main/java/org/karnak/frontend/component/AbstractDialog.java index b1483daa4..258886eb9 100644 --- a/src/main/java/org/karnak/frontend/component/AbstractDialog.java +++ b/src/main/java/org/karnak/frontend/component/AbstractDialog.java @@ -20,6 +20,7 @@ public abstract class AbstractDialog extends Composite { private static final long serialVersionUID = 1L; protected VerticalLayout mainLayout; + private MessageBox messageBox; protected abstract void createMainLayout(); diff --git a/src/main/java/org/karnak/frontend/component/ConfirmDialog.java b/src/main/java/org/karnak/frontend/component/ConfirmDialog.java index 56f7706d7..f4b2fe1a3 100644 --- a/src/main/java/org/karnak/frontend/component/ConfirmDialog.java +++ b/src/main/java/org/karnak/frontend/component/ConfirmDialog.java @@ -33,10 +33,15 @@ public class ConfirmDialog extends Composite { private VerticalLayout mainLayout; private HorizontalLayout headerLayout; + private Span titleText; + private Div messageLayout; + private HorizontalLayout buttonsLayout; + private Button yesBtn; + private Button noBtn; // DATA diff --git a/src/main/java/org/karnak/frontend/component/MessageBox.java b/src/main/java/org/karnak/frontend/component/MessageBox.java index 62c1a8543..0fb87fd99 100644 --- a/src/main/java/org/karnak/frontend/component/MessageBox.java +++ b/src/main/java/org/karnak/frontend/component/MessageBox.java @@ -25,12 +25,16 @@ public class MessageBox extends Composite
{ // UI COMPONENTS private HorizontalLayout layout; + private Div titleDiv; + private Div contentDiv; + private IronIcon icon; // DATA private Message message; + private final MessageType type; public MessageBox(MessageType type) { diff --git a/src/main/java/org/karnak/frontend/component/WarningConfirmDialog.java b/src/main/java/org/karnak/frontend/component/WarningConfirmDialog.java index 9b0e5140e..c9315089d 100644 --- a/src/main/java/org/karnak/frontend/component/WarningConfirmDialog.java +++ b/src/main/java/org/karnak/frontend/component/WarningConfirmDialog.java @@ -27,21 +27,35 @@ public class WarningConfirmDialog extends Composite { private static final long serialVersionUID = 1L; + private static final String DEFAULT_TITLE = "Warning"; + private static final String DEFAULT_VALIDATE = "Validate"; + private static final String DEFAULT_CANCEL = "Cancel"; + private final Div messageLayout; + // DATA private final String valueTitle; + private final String valueValidate; + private final String valueCancel; + // UI COMPONENT private Dialog dialog; + private VerticalLayout mainLayout; + private HorizontalLayout headerLayout; + private Span titleText; + private HorizontalLayout buttonsLayout; + private Button buttonValidate; + private Button buttonCancel; public WarningConfirmDialog(Div messageLayout) { diff --git a/src/main/java/org/karnak/frontend/dicom/DicomMainView.java b/src/main/java/org/karnak/frontend/dicom/DicomMainView.java index 0d23668f8..5b8560ba9 100644 --- a/src/main/java/org/karnak/frontend/dicom/DicomMainView.java +++ b/src/main/java/org/karnak/frontend/dicom/DicomMainView.java @@ -30,20 +30,32 @@ @PageTitle("KARNAK - DICOM Tools") @Secured({"ROLE_admin"}) public class DicomMainView extends VerticalLayout { + public static final String VIEW_NAME = "DICOM Tools"; + public static final String ROUTE = "dicom"; + private static final long serialVersionUID = 1L; // UI COMPONENTS private DicomWebToolsBrand dicomWebToolsBrand; + private Tabs menu; + private Tab tabDicomEchoView; + private Tab tabDicomWorkListView; + private Tab tabMonitorView; + private Map tabsToPages; + private AbstractView pageDicomEchoView; + private AbstractView pageDicomWorkListView; + private AbstractView pageMonitorView; + private Set pagesShown; // DATA diff --git a/src/main/java/org/karnak/frontend/dicom/DicomWebToolsBrand.java b/src/main/java/org/karnak/frontend/dicom/DicomWebToolsBrand.java index 34d3adf77..f4bc36e75 100644 --- a/src/main/java/org/karnak/frontend/dicom/DicomWebToolsBrand.java +++ b/src/main/java/org/karnak/frontend/dicom/DicomWebToolsBrand.java @@ -20,6 +20,7 @@ public class DicomWebToolsBrand extends Composite
{ private static final String TEXT = "Dicom Web Tools"; private final Div div; + private Span text; public DicomWebToolsBrand() { diff --git a/src/main/java/org/karnak/frontend/dicom/FileFormatFilter.java b/src/main/java/org/karnak/frontend/dicom/FileFormatFilter.java index 8a80278aa..4217a5602 100644 --- a/src/main/java/org/karnak/frontend/dicom/FileFormatFilter.java +++ b/src/main/java/org/karnak/frontend/dicom/FileFormatFilter.java @@ -24,9 +24,13 @@ public class FileFormatFilter extends FileFilter { private final Map fExtensions; + private String fDescription; + private String fFullDescription; + private String fDefaultExtension; + private boolean fUseExtensionsInDescription; public FileFormatFilter(String extension, String description) { diff --git a/src/main/java/org/karnak/frontend/dicom/PortField.java b/src/main/java/org/karnak/frontend/dicom/PortField.java index 6f6b4d4e2..c7ad5695e 100644 --- a/src/main/java/org/karnak/frontend/dicom/PortField.java +++ b/src/main/java/org/karnak/frontend/dicom/PortField.java @@ -15,5 +15,6 @@ public class PortField extends IntegerField { private static final long serialVersionUID = -8643695885164227059L; - public PortField() {} + public PortField() { + } } diff --git a/src/main/java/org/karnak/frontend/dicom/Util.java b/src/main/java/org/karnak/frontend/dicom/Util.java index 06fda7256..69db135e6 100644 --- a/src/main/java/org/karnak/frontend/dicom/Util.java +++ b/src/main/java/org/karnak/frontend/dicom/Util.java @@ -97,7 +97,7 @@ public static void getNetworkInfo(StringBuilder result) { // Force getting hostname inetAddress.getHostName(); result.append("
Inet address: "); - result.append(inetAddress.toString()); + result.append(inetAddress); } result.append("
"); } @@ -354,7 +354,8 @@ public static void getWadoResponse( builder .GET() .uri(new URI("https://httpbin.org/get")) - .header("User-Agent", "Mozilla/5.0 Firefox/43.0") // add request header + .header("User-Agent", "Mozilla/5.0 Firefox/43.0") // add request + // header .build(); long starTime = System.currentTimeMillis(); diff --git a/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoSelectionDialog.java b/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoSelectionDialog.java index a157f796c..b098a1e3a 100644 --- a/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoSelectionDialog.java +++ b/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoSelectionDialog.java @@ -42,23 +42,32 @@ public class DicomEchoSelectionDialog extends AbstractDialog { private static final long serialVersionUID = 1L; // CONTROLLER - private DicomEchoSelectionLogic logic = new DicomEchoSelectionLogic(this); + private final DicomEchoSelectionLogic logic = new DicomEchoSelectionLogic(this); // UI COMPONENTS private Dialog dialog; private Div titleBar; + private FormLayout formLayout; + private Select dicomNodeTypeSelector; + private ComboBox dicomNodeSelector; + private HorizontalLayout buttonBar; + private Button cancelBtn; + private Button selectBtn; // DATA private List dicomNodeTypes; + private ListDataProvider dataProviderForDicomNodeTypes; + private DicomNodeList dicomNodes; + private ListDataProvider dataProviderForDicomNodes; public DicomEchoSelectionDialog() { diff --git a/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoSelectionLogic.java b/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoSelectionLogic.java index 78719aec8..a20894503 100644 --- a/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoSelectionLogic.java +++ b/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoSelectionLogic.java @@ -17,7 +17,7 @@ public class DicomEchoSelectionLogic { // DIALOG - private DicomEchoSelectionDialog dialog; + private final DicomEchoSelectionDialog dialog; public DicomEchoSelectionLogic(DicomEchoSelectionDialog dialog) { this.dialog = dialog; diff --git a/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoView.java b/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoView.java index 71224880b..a6440eb35 100644 --- a/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoView.java +++ b/src/main/java/org/karnak/frontend/dicom/echo/DicomEchoView.java @@ -37,20 +37,28 @@ import org.karnak.frontend.dicom.PortField; import org.karnak.frontend.dicom.echo.DicomEchoSelectionDialog.DicomNodeSelectionEvent; -/** Calling Order 1) constructor 2) setParameter 3) beforeEnter */ +/** + * Calling Order 1) constructor 2) setParameter 3) beforeEnter + */ @SuppressWarnings("serial") public class DicomEchoView extends AbstractView implements HasUrlParameter { public static final String VIEW_NAME = "Dicom Echo"; + private static final long serialVersionUID = 1L; private static final String PARAMETER_CALLING_AET = "callingAET"; + private static final String PARAMETER_CALLED_AET = "calledAET"; + private static final String PARAMETER_CALLED_HOSTNAME = "calledHostname"; + private static final String PARAMETER_CALLED_PORT = "calledPort"; + private static final String PARAMETER_ACTION = "action"; private static final String ACTION_ECHO = "echo"; + public static final String ERROR_MESSAGE = "This filed is mandatory"; // CONTROLLER @@ -62,28 +70,44 @@ public class DicomEchoView extends AbstractView implements HasUrlParameter binder; // PARAMETERS private String callingAetParam; + private String dicomNodeAetParam; + private String dicomNodeHostnameParam; + private String dicomNodePortParam; + private String actionParam; public DicomEchoView() { diff --git a/src/main/java/org/karnak/frontend/dicom/monitor/MonitorLogic.java b/src/main/java/org/karnak/frontend/dicom/monitor/MonitorLogic.java index 7ad3bd7aa..79263265d 100644 --- a/src/main/java/org/karnak/frontend/dicom/monitor/MonitorLogic.java +++ b/src/main/java/org/karnak/frontend/dicom/monitor/MonitorLogic.java @@ -25,10 +25,12 @@ public class MonitorLogic { // SERVICES private final DicomEchoService dicomEchoService; + private final WadoService wadoService; // DATA private DicomNodeList dicomNodeListSelected; + private WadoNodeList wadoNodeListSelected; public MonitorLogic(MonitorView view) { diff --git a/src/main/java/org/karnak/frontend/dicom/monitor/MonitorView.java b/src/main/java/org/karnak/frontend/dicom/monitor/MonitorView.java index 6802d84fd..400c29e86 100644 --- a/src/main/java/org/karnak/frontend/dicom/monitor/MonitorView.java +++ b/src/main/java/org/karnak/frontend/dicom/monitor/MonitorView.java @@ -36,17 +36,27 @@ public class MonitorView extends AbstractView { // Dicom Layout private HorizontalLayout dicomEchoLayout; + private H6 dicomEchoLayoutTitle; + private Select dicomEchoNodeListSelector; + private Button dicomEchoBtn; + // WADO Layout private HorizontalLayout wadoLayout; + private H6 wadoLayoutTitle; + private Select wadoNodeListSelector; + private Button wadoBtn; + // Result Layout private VerticalLayout resultLayout; + private H6 resultTitle; + private Div resultDiv; public MonitorView() { @@ -64,7 +74,8 @@ public void displayStatus(String status) { resultLayout.setVisible(true); } - private void init() {} + private void init() { + } private void createView() { setSizeFull(); diff --git a/src/main/java/org/karnak/frontend/dicom/mwl/DicomPane.java b/src/main/java/org/karnak/frontend/dicom/mwl/DicomPane.java index 07b9711ef..2d271e0da 100644 --- a/src/main/java/org/karnak/frontend/dicom/mwl/DicomPane.java +++ b/src/main/java/org/karnak/frontend/dicom/mwl/DicomPane.java @@ -27,16 +27,25 @@ public class DicomPane extends Composite { // CONTROLLER private final DicomPaneLogic logic = new DicomPaneLogic(this); + // DATA private final Attributes dcm; + // UI COMPONENTS private Dialog currentDialog; + private VerticalLayout mainLayout; + private Div titleBar; + private TextArea contentFld; + private HorizontalLayout buttonBar; + private Button cancelButton; + private Anchor downloadDicomAnchor; + private Anchor downloadTextAnchor; public DicomPane(Attributes dcm) { diff --git a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListGrid.java b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListGrid.java index 3fa14893f..5d33e1c9e 100644 --- a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListGrid.java +++ b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListGrid.java @@ -21,7 +21,8 @@ public class DicomWorkListGrid extends Grid { - @Serial private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; List params = List.of( @@ -59,17 +60,17 @@ private void addColumn(DicomParam p) { .setKey(String.valueOf(tag)); } else { addColumn( - a -> { - Attributes parent = a; - for (int k = 0; k < pSeq.length; k++) { - Attributes pn = parent.getNestedDataset(pSeq[k]); - if (pn == null) { - break; - } - parent = pn; - } - return getText(parent, tag); - }) + a -> { + Attributes parent = a; + for (int k = 0; k < pSeq.length; k++) { + Attributes pn = parent.getNestedDataset(pSeq[k]); + if (pn == null) { + break; + } + parent = pn; + } + return getText(parent, tag); + }) .setHeader(Keyword.valueOf(tag)) .setSortable(true) .setKey(String.valueOf(tag)); diff --git a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListLogic.java b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListLogic.java index 904dd1138..09140d2d2 100644 --- a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListLogic.java +++ b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListLogic.java @@ -45,49 +45,49 @@ public void query(WorkListQueryData queryData) { int[] sps = {Tag.ScheduledProcedureStepSequence}; DicomParam[] RETURN_KEYS = { - new DicomParam(Tag.AccessionNumber, queryData.getAccessionNumber()), - CFind.IssuerOfAccessionNumberSequence, - CFind.ReferringPhysicianName, - new DicomParam(Tag.PatientName, queryData.getPatientName()), - new DicomParam(Tag.PatientID, queryData.getPatientId()), - CFind.IssuerOfPatientID, - CFind.PatientBirthDate, - CFind.PatientSex, - ModalityWorklist.PatientWeight, - ModalityWorklist.MedicalAlerts, - ModalityWorklist.Allergies, - ModalityWorklist.PregnancyStatus, - CFind.StudyInstanceUID, - ModalityWorklist.RequestingPhysician, - ModalityWorklist.RequestingService, - ModalityWorklist.RequestedProcedureDescription, - ModalityWorklist.RequestedProcedureCodeSequence, - new DicomParam(Tag.AdmissionID, queryData.getAdmissionId()), - ModalityWorklist.IssuerOfAdmissionIDSequence, - ModalityWorklist.SpecialNeeds, - ModalityWorklist.CurrentPatientLocation, - ModalityWorklist.PatientState, - ModalityWorklist.RequestedProcedureID, - ModalityWorklist.RequestedProcedurePriority, - ModalityWorklist.PatientTransportArrangements, - ModalityWorklist.PlacerOrderNumberImagingServiceRequest, - ModalityWorklist.FillerOrderNumberImagingServiceRequest, - ModalityWorklist.ConfidentialityConstraintOnPatientDataDescription, - // Scheduled Procedure Step Sequence - new DicomParam(sps, Tag.Modality, modalityStr), - ModalityWorklist.RequestedContrastAgent, - new DicomParam(sps, Tag.ScheduledStationAETitle, queryData.getScheduledStationAet()), - new DicomParam( - sps, Tag.ScheduledProcedureStepStartDate, getDate(queryData.getScheduledFrom())), - new DicomParam(sps, Tag.ScheduledProcedureStepEndDate, getDate(queryData.getScheduledTo())), - ModalityWorklist.ScheduledPerformingPhysicianName, - ModalityWorklist.ScheduledProcedureStepDescription, - ModalityWorklist.ScheduledProcedureStepID, - ModalityWorklist.ScheduledStationName, - ModalityWorklist.ScheduledProcedureStepLocation, - ModalityWorklist.PreMedication, - ModalityWorklist.ScheduledProcedureStepStatus, - ModalityWorklist.ScheduledProtocolCodeSequence + new DicomParam(Tag.AccessionNumber, queryData.getAccessionNumber()), + CFind.IssuerOfAccessionNumberSequence, + CFind.ReferringPhysicianName, + new DicomParam(Tag.PatientName, queryData.getPatientName()), + new DicomParam(Tag.PatientID, queryData.getPatientId()), + CFind.IssuerOfPatientID, + CFind.PatientBirthDate, + CFind.PatientSex, + ModalityWorklist.PatientWeight, + ModalityWorklist.MedicalAlerts, + ModalityWorklist.Allergies, + ModalityWorklist.PregnancyStatus, + CFind.StudyInstanceUID, + ModalityWorklist.RequestingPhysician, + ModalityWorklist.RequestingService, + ModalityWorklist.RequestedProcedureDescription, + ModalityWorklist.RequestedProcedureCodeSequence, + new DicomParam(Tag.AdmissionID, queryData.getAdmissionId()), + ModalityWorklist.IssuerOfAdmissionIDSequence, + ModalityWorklist.SpecialNeeds, + ModalityWorklist.CurrentPatientLocation, + ModalityWorklist.PatientState, + ModalityWorklist.RequestedProcedureID, + ModalityWorklist.RequestedProcedurePriority, + ModalityWorklist.PatientTransportArrangements, + ModalityWorklist.PlacerOrderNumberImagingServiceRequest, + ModalityWorklist.FillerOrderNumberImagingServiceRequest, + ModalityWorklist.ConfidentialityConstraintOnPatientDataDescription, + // Scheduled Procedure Step Sequence + new DicomParam(sps, Tag.Modality, modalityStr), + ModalityWorklist.RequestedContrastAgent, + new DicomParam(sps, Tag.ScheduledStationAETitle, queryData.getScheduledStationAet()), + new DicomParam( + sps, Tag.ScheduledProcedureStepStartDate, getDate(queryData.getScheduledFrom())), + new DicomParam(sps, Tag.ScheduledProcedureStepEndDate, getDate(queryData.getScheduledTo())), + ModalityWorklist.ScheduledPerformingPhysicianName, + ModalityWorklist.ScheduledProcedureStepDescription, + ModalityWorklist.ScheduledProcedureStepID, + ModalityWorklist.ScheduledStationName, + ModalityWorklist.ScheduledProcedureStepLocation, + ModalityWorklist.PreMedication, + ModalityWorklist.ScheduledProcedureStepStatus, + ModalityWorklist.ScheduledProtocolCodeSequence }; DicomNode workListNode = diff --git a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListSelectionDialog.java b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListSelectionDialog.java index f8adee087..25d6ba6ca 100644 --- a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListSelectionDialog.java +++ b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListSelectionDialog.java @@ -36,20 +36,26 @@ public class DicomWorkListSelectionDialog extends AbstractDialog { private static final long serialVersionUID = 1L; // CONTROLLER - private DicomWorkListSelectionLogic logic = new DicomWorkListSelectionLogic(this); + private final DicomWorkListSelectionLogic logic = new DicomWorkListSelectionLogic(this); // UI COMPONENTS private Dialog dialog; private Div titleBar; + private FormLayout formLayout; + private Select worklistNodeSelector; + private HorizontalLayout buttonBar; + private Button cancelBtn; + private Button selectBtn; // DATA private DicomNodeList workListNodes; + private ListDataProvider dataProviderForWorkListNodes; public DicomWorkListSelectionDialog() { diff --git a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListSelectionLogic.java b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListSelectionLogic.java index 345821f20..2c4e01796 100644 --- a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListSelectionLogic.java +++ b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListSelectionLogic.java @@ -17,7 +17,7 @@ public class DicomWorkListSelectionLogic { // DIALOG - private DicomWorkListSelectionDialog dialog; + private final DicomWorkListSelectionDialog dialog; public DicomWorkListSelectionLogic(DicomWorkListSelectionDialog view) { this.dialog = view; diff --git a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListView.java b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListView.java index c432a5a1e..bffea04ca 100644 --- a/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListView.java +++ b/src/main/java/org/karnak/frontend/dicom/mwl/DicomWorkListView.java @@ -45,15 +45,21 @@ import org.karnak.frontend.dicom.PortField; import org.karnak.frontend.dicom.mwl.DicomWorkListSelectionDialog.WorkListSelectionEvent; -/** Calling Order 1) constructor 2) setParameter 3) beforeEnter */ +/** + * Calling Order 1) constructor 2) setParameter 3) beforeEnter + */ public class DicomWorkListView extends AbstractView implements HasUrlParameter { private static final long serialVersionUID = 1L; private static final String PARAMETER_CALLING_AET = "callingAET"; + private static final String PARAMETER_WORKLIST_AET = "worklistAet"; + private static final String PARAMETER_WORKLIST_HOSTNAME = "worklistHostname"; + private static final String PARAMETER_WORKLIST_PORT = "worklistPort"; + private static final String PARAMETER_ACTION = "action"; private static final String ACTION_QUERY = "query"; @@ -66,46 +72,76 @@ public class DicomWorkListView extends AbstractView implements HasUrlParameter scheduledModalitySelector; + private TextField patientIdfld; + private TextField admissionIdFld; + private DatePicker scheduledFromFld; + private DatePicker scheduledToFld; + private TextField patientNameFld; + private TextField accessionNumberFld; + private HorizontalLayout buttonBar; + private Button clearBtn; + private Button selectWorkListBtn; + private Button queryBtn; + // Query Result private VerticalLayout queryResultLayout; + private H6 queryResultTitle; + private DicomWorkListGrid queryResultGrid; private DicomPane dicomPane; // DATA private WorkListQueryData workListQueryData; + private Binder binderForWorkListQuery; + private List attributes; + private ListDataProvider dataProviderForAttributes; // PARAMETERS private String callingAetParam; + private String worklistAetParam; + private String worklistHostnameParam; + private String worklistPortParam; + private String actionParam; public DicomWorkListView() { diff --git a/src/main/java/org/karnak/frontend/extid/CSVDialog.java b/src/main/java/org/karnak/frontend/extid/CSVDialog.java index f11672a50..43b06c5cf 100644 --- a/src/main/java/org/karnak/frontend/extid/CSVDialog.java +++ b/src/main/java/org/karnak/frontend/extid/CSVDialog.java @@ -28,7 +28,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import liquibase.util.csv.opencsv.CSVReader; -import org.karnak.backend.cache.CachedPatient; +import org.karnak.backend.cache.Patient; import org.karnak.backend.data.entity.ProjectEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,27 +36,47 @@ public class CSVDialog extends Dialog { private static final Logger LOGGER = LoggerFactory.getLogger(CSVDialog.class); + private static final String EXTERNAL_PSEUDONYM = "External Pseudonym"; + private static final String PATIENT_ID = "Patient ID"; + private static final String PATIENT_FIRST_NAME = "Patient first name"; + private static final String PATIENT_LAST_NAME = "Patient last name"; + private static final String ISSUER_OF_PATIENT_ID = "Issuer of patient ID"; + private static final String TITLE = "Upload CSV that contains the correspondence table with the externals pseudonyms"; + private final String[] selectValues = { - "", EXTERNAL_PSEUDONYM, PATIENT_ID, PATIENT_FIRST_NAME, PATIENT_LAST_NAME, ISSUER_OF_PATIENT_ID + "", EXTERNAL_PSEUDONYM, PATIENT_ID, PATIENT_FIRST_NAME, PATIENT_LAST_NAME, + ISSUER_OF_PATIENT_ID }; - private final List patientsList; + + private final List patientsList; + private NumberField fromLineField; + private Button readCSVButton; + private Button cancelButton; + private Div divGridContent; + private Div errorMsg; + private Div divTitle; + private Grid csvGrid; + private List> listOfSelect; + private List allRows; + private HashMap selectValuesPositionHashMap; + private final transient ProjectEntity projectEntity; public CSVDialog(InputStream inputStream, char separator, ProjectEntity projectEntity) { @@ -222,8 +242,8 @@ private void readCSVPatients() { selectValuesPositionHashMap.get(ISSUER_OF_PATIENT_ID).equals(-1) ? "" : row[selectValuesPositionHashMap.get(ISSUER_OF_PATIENT_ID)]; - final CachedPatient newPatient = - new CachedPatient( + final Patient newPatient = + new Patient( row[selectValuesPositionHashMap.get(EXTERNAL_PSEUDONYM)], row[selectValuesPositionHashMap.get(PATIENT_ID)], row[selectValuesPositionHashMap.get(PATIENT_FIRST_NAME)], @@ -241,7 +261,7 @@ public Button getReadCSVButton() { return readCSVButton; } - public List getPatientsList() { + public List getPatientsList() { return patientsList; } diff --git a/src/main/java/org/karnak/frontend/extid/DuplicateDialog.java b/src/main/java/org/karnak/frontend/extid/DuplicateDialog.java index d55ac59df..07a996655 100644 --- a/src/main/java/org/karnak/frontend/extid/DuplicateDialog.java +++ b/src/main/java/org/karnak/frontend/extid/DuplicateDialog.java @@ -15,17 +15,18 @@ import com.vaadin.flow.component.html.Div; import java.util.Collection; import java.util.List; -import org.karnak.backend.cache.CachedPatient; -import org.karnak.backend.cache.PseudonymPatient; +import org.karnak.backend.cache.Patient; public class DuplicateDialog extends Dialog { - private Collection duplicateList; - private Grid grid; + + private final Collection duplicateList; + + private Grid grid; public DuplicateDialog( - String title, String text, Collection duplicateList, String buttonText) { + String title, String text, Collection duplicateList, String buttonText) { removeAll(); - this.duplicateList = (List) (List) duplicateList; + this.duplicateList = (List) (List) duplicateList; Div divTitle = new Div(); divTitle.setText(title); @@ -52,15 +53,11 @@ public DuplicateDialog( public void setGridElement() { grid = new Grid<>(); - grid.addColumn(CachedPatient::getPseudonym).setHeader("External pseudonym").setSortable(true); - grid.addColumn(CachedPatient::getPatientId).setHeader("Patient ID").setSortable(true); - grid.addColumn(CachedPatient::getPatientFirstName) - .setHeader("Patient first name") - .setSortable(true); - grid.addColumn(CachedPatient::getPatientLastName) - .setHeader("Patient last name") - .setSortable(true); - grid.addColumn(CachedPatient::getIssuerOfPatientId) + grid.addColumn(Patient::getPseudonym).setHeader("External pseudonym").setSortable(true); + grid.addColumn(Patient::getPatientId).setHeader("Patient ID").setSortable(true); + grid.addColumn(Patient::getPatientFirstName).setHeader("Patient first name").setSortable(true); + grid.addColumn(Patient::getPatientLastName).setHeader("Patient last name").setSortable(true); + grid.addColumn(Patient::getIssuerOfPatientId) .setHeader("Issuer of patient ID") .setSortable(true); grid.setItems(duplicateList); diff --git a/src/main/java/org/karnak/frontend/extid/ExternalIDForm.java b/src/main/java/org/karnak/frontend/extid/ExternalIDForm.java index a7b61b5dc..da348e537 100644 --- a/src/main/java/org/karnak/frontend/extid/ExternalIDForm.java +++ b/src/main/java/org/karnak/frontend/extid/ExternalIDForm.java @@ -19,7 +19,7 @@ import com.vaadin.flow.data.binder.Binder; import com.vaadin.flow.data.validator.StringLengthValidator; import org.apache.commons.lang3.StringUtils; -import org.karnak.backend.cache.CachedPatient; +import org.karnak.backend.cache.Patient; import org.karnak.backend.data.entity.ProjectEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,23 +27,33 @@ public class ExternalIDForm extends Div { protected static final Logger LOGGER = LoggerFactory.getLogger(ExternalIDForm.class); + private static final String ERROR_MESSAGE_PATIENT = "Length must be between 1 and 50."; - private final Binder binder; + private final Binder binder; + private transient ProjectEntity projectEntity; + private TextField externalIdField; + private TextField patientIdField; + private TextField patientFirstNameField; + private TextField patientLastNameField; + private TextField issuerOfPatientIdField; + private Button addPatientButton; + private Button clearFieldsButton; + private Div addedPatientLabelDiv; public ExternalIDForm() { setSizeFull(); - binder = new BeanValidationBinder<>(CachedPatient.class); + binder = new BeanValidationBinder<>(Patient.class); setElements(); setBinder(); @@ -138,9 +148,9 @@ public void setBinder() { .bind("issuerOfPatientId"); } - public CachedPatient getNewPatient() { - CachedPatient newPatient = - new CachedPatient( + public Patient getNewPatient() { + Patient newPatient = + new Patient( externalIdField.getValue(), patientIdField.getValue(), patientFirstNameField.getValue(), diff --git a/src/main/java/org/karnak/frontend/extid/ExternalIDGrid.java b/src/main/java/org/karnak/frontend/extid/ExternalIDGrid.java index 5ba61dcd0..b209d6ad0 100644 --- a/src/main/java/org/karnak/frontend/extid/ExternalIDGrid.java +++ b/src/main/java/org/karnak/frontend/extid/ExternalIDGrid.java @@ -27,53 +27,79 @@ import java.util.WeakHashMap; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; -import org.karnak.backend.cache.CachedPatient; +import org.karnak.backend.cache.Patient; import org.karnak.backend.cache.PatientClient; -import org.karnak.backend.cache.PseudonymPatient; import org.karnak.backend.config.AppConfig; import org.karnak.backend.data.entity.ProjectEntity; import org.karnak.backend.util.PatientClientUtil; import org.vaadin.klaudeta.PaginatedGrid; -public class ExternalIDGrid extends PaginatedGrid { +public class ExternalIDGrid extends PaginatedGrid { private static final String ERROR_MESSAGE_PATIENT = "Length must be between 1 and 50."; + private static final String LABEL_SAVE = "Save"; + private static final String LABEL_CANCEL = "Cancel"; + private static final String LABEL_FILTER = "Filter"; - private final Binder binder; - private final List patientList; + + private final Binder binder; + + private final List patientList; + private transient PatientClient externalIDCache; + private transient ProjectEntity projectEntity; + private Button deletePatientButton; + private Button saveEditPatientButton; + private Button cancelEditPatientButton; - private Editor editor; + + private Editor editor; + private Collection