diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml
index 7a482c8..868f86b 100644
--- a/.github/workflows/maven-publish.yml
+++ b/.github/workflows/maven-publish.yml
@@ -4,6 +4,7 @@
name: Java CI Publish with Maven
on:
+ workflow_dispatch:
pull_request:
types: [closed]
branches: [develop]
diff --git a/mii-dsf-process-projectathon-data-transfer/pom.xml b/mii-dsf-process-projectathon-data-transfer/pom.xml
index caabcb6..cf27e48 100644
--- a/mii-dsf-process-projectathon-data-transfer/pom.xml
+++ b/mii-dsf-process-projectathon-data-transfer/pom.xml
@@ -1,6 +1,6 @@
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
mii-process-projectathon-data-transfer
@@ -8,7 +8,7 @@
de.medizininformatik-initiative
mii-dsf-processes
- 0.1.0-SNAPSHOT
+ 0.1.0-RC1
@@ -26,6 +26,11 @@
hapi-fhir-client
provided
+
+ org.apache.tika
+ tika-core
+ provided
+
de.medizininformatik-initiative
@@ -67,10 +72,15 @@
-classpath
- de.medizininformatik_initiative.processes.documentation.generator.DocumentationGenerator
- de.medizininformatik_initiative.processes.projectathon.data_transfer.spring.config
+
+ de.medizininformatik_initiative.processes.documentation.generator.DocumentationGenerator
+
+
+ de.medizininformatik_initiative.processes.projectathon.data_transfer
+
true
+ true
compile
${project.basedir}
@@ -92,12 +102,19 @@
${project.artifactId}
${project.version}
+
+ org.apache.tika
+ tika-core
+ ${apache.tika.version}
+
- ../mii-dsf-processes-docker-test-setup/dic/bpe/process
+
+ ../mii-dsf-processes-docker-test-setup/dic/bpe/process/${project.artifactId}-${project.version}
+
- copy-hapi-fhir-client/dic
+ copy-dependencies/dic
package
copy
@@ -126,12 +143,19 @@
${project.artifactId}
${project.version}
+
+ org.apache.tika
+ tika-core
+ ${apache.tika.version}
+
- ../mii-dsf-processes-docker-test-setup/cos/bpe/process
+
+ ../mii-dsf-processes-docker-test-setup/cos/bpe/process/${project.artifactId}-${project.version}
+
- copy-hapi-fhir-client/cos
+ copy-dependencies/cos
package
copy
@@ -147,6 +171,23 @@
../mii-dsf-processes-docker-test-setup/cos/bpe/plugin
+
+ copy-dependencies/assembly
+ package
+
+ copy
+
+
+
+
+ org.apache.tika
+ tika-core
+ ${apache.tika.version}
+
+
+ ${project.build.directory}/lib
+
+
@@ -155,28 +196,36 @@
- ../mii-dsf-processes-docker-test-setup/dic/bpe/process
+
+ ../mii-dsf-processes-docker-test-setup/dic/bpe/process/${project.artifactId}-${project.version}
+
- ${project.artifactId}-${project.version}.jar
+ **
false
- ../mii-dsf-processes-docker-test-setup/dic/bpe/plugin
+
+ ../mii-dsf-processes-docker-test-setup/dic/bpe/plugin
+
hapi-fhir-client-${hapi.version}.jar
false
- ../mii-dsf-processes-docker-test-setup/cos/bpe/process
+
+ ../mii-dsf-processes-docker-test-setup/cos/bpe/process/${project.artifactId}-${project.version}
+
- ${project.artifactId}-${project.version}.jar
+ **
false
- ../mii-dsf-processes-docker-test-setup/cos/bpe/plugin
+
+ ../mii-dsf-processes-docker-test-setup/cos/bpe/plugin
+
hapi-fhir-client-${hapi.version}.jar
@@ -185,6 +234,25 @@
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ zip-assembly
+ install
+
+ single
+
+
+
+
+ false
+
+ src/assembly/zip.xml
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java
index e779d66..e3b96b6 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java
@@ -90,8 +90,8 @@ public void onContextRefreshedEvent(ContextRefreshedEvent event)
try
{
logger.info(
- "Testing connection to projectathon FHIR server with {trustStorePath: {}, certificatePath: {}, privateKeyPath: {}, privateKeyPassword: {},"
- + " basicAuthUsername {}, basicAuthPassword {}, bearerToken {}, serverBase: {}, proxyUrl {}, proxyUsername, proxyPassword {}}",
+ "Testing connection to KDS FHIR server with {trustStorePath: {}, certificatePath: {}, privateKeyPath: {}, privateKeyPassword: {},"
+ + " basicAuthUsername {}, basicAuthPassword {}, bearerToken {}, serverBase: {}, proxyUrl {}, proxyUsername {}, proxyPassword {}}",
trustStorePath, certificatePath, privateKeyPath, privateKeyPassword != null ? "***" : "null",
kdsServerBasicAuthUsername, kdsServerBasicAuthPassword != null ? "***" : "null",
kdsServerBearerToken != null ? "***" : "null", kdsServerBase, proxyUrl, proxyUsername,
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientImpl.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientImpl.java
index 3a64d47..0dd29a4 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientImpl.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientImpl.java
@@ -6,15 +6,11 @@
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.DocumentReference;
import org.hl7.fhir.r4.model.IdType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.KdsClient;
public class KdsFhirClientImpl implements KdsFhirClient
{
- private static final Logger logger = LoggerFactory.getLogger(KdsFhirClientImpl.class);
-
private KdsClient kdsClient;
public KdsFhirClientImpl(KdsClient kdsClient)
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientStub.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientStub.java
index 1f09efb..da77ddf 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientStub.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientStub.java
@@ -14,15 +14,11 @@
import org.hl7.fhir.r4.model.DocumentReference;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.ResourceType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.KdsClient;
public final class KdsFhirClientStub implements KdsFhirClient
{
- private static final Logger logger = LoggerFactory.getLogger(KdsFhirClientStub.class);
-
private final KdsClient kdsClient;
public KdsFhirClientStub(KdsClient kdsClient)
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProviderImpl.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProviderImpl.java
index ec0c05d..5a72db2 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProviderImpl.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProviderImpl.java
@@ -37,7 +37,7 @@
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
-import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper;
import de.rwh.utils.crypto.io.PemIo;
public class KeyProviderImpl implements KeyProvider, InitializingBean
@@ -152,17 +152,16 @@ public void onContextRefreshedEvent(ContextRefreshedEvent event)
else if (output.getTotal() == 0)
{
logger.info("Creating new PublicKey Bundle on DSF FHIR server...");
- Bundle bundleToCreate = getPublicKeyBundle();
+ Bundle bundleToCreate = createPublicKeyBundle();
bundleOnServer = clientProvider.getLocalWebserviceClient().createConditionaly(bundleToCreate,
"identifier=" + CODESYSTEM_MII_CRYPTOGRAPHY + "|"
+ CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY);
}
else
{
- logger.warn("Exist > 1 Bundle with identifier={}|{}", CODESYSTEM_MII_CRYPTOGRAPHY,
- CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY);
- throw new RuntimeException("Exist > 1 Bundle with identifier=" + CODESYSTEM_MII_CRYPTOGRAPHY + "|"
- + CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY);
+ throw new RuntimeException(
+ "Exist " + output.getTotal() + " Bundle with identifier=" + CODESYSTEM_MII_CRYPTOGRAPHY
+ + "|" + CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY + ", expected only one");
}
logger.info("PublicKey Bundle has id='{}'", bundleOnServer.getId());
@@ -175,7 +174,7 @@ else if (output.getTotal() == 0)
}
}
- private Bundle getPublicKeyBundle()
+ private Bundle createPublicKeyBundle()
{
Date date = new Date();
@@ -202,8 +201,7 @@ private Bundle getPublicKeyBundle()
readAccessHelper.addAll(bundle);
- logger.debug("Created Bundle: {}",
- FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle));
+ LoggingHelper.logDebugBundle("Created Bundle", bundle);
return bundle;
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java
index db7beb1..b6d0aa0 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java
@@ -24,19 +24,17 @@ public class RsaAesGcmUtil
private static final String RSA_CIPHER = "RSA/ECB/PKCS1Padding";
private static final int RSA_KEY_LENGTH = 4096;
private static final int ENCRYPTED_AES_KEY_LENGTH = 512;
- /**
- * AAD: some random bytes
- */
- private static final byte[] AAD = "JLCbSbIk5VAvBtKs4ypnDw3AJRfSBWXFHUxl78WBJw".getBytes(StandardCharsets.UTF_8);
- public static byte[] encrypt(PublicKey publicKey, byte[] data)
+ public static byte[] encrypt(PublicKey publicKey, byte[] data, String sendingOrganizationIdentifier,
+ String receivingOrganizationIdentifier)
throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, ShortBufferException
{
SecretKey aesKey = AesGcmUtil.generateAES256Key();
+ byte[] aad = getAad(sendingOrganizationIdentifier, receivingOrganizationIdentifier);
byte[] encryptedAesKey = encryptRsa(aesKey, publicKey);
- byte[] encryptedData = AesGcmUtil.encrypt(data, AAD, aesKey);
+ byte[] encryptedData = AesGcmUtil.encrypt(data, aad, aesKey);
if (encryptedAesKey.length != ENCRYPTED_AES_KEY_LENGTH)
throw new IllegalStateException("Encrypted AES key length = " + ENCRYPTED_AES_KEY_LENGTH + " expected");
@@ -48,7 +46,8 @@ public static byte[] encrypt(PublicKey publicKey, byte[] data)
return output;
}
- public static byte[] decrypt(PrivateKey privateKey, byte[] encrypted)
+ public static byte[] decrypt(PrivateKey privateKey, byte[] encrypted, String sendingOrganizationIdentifier,
+ String receivingOrganizationIdentifier)
throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException,
NoSuchAlgorithmException, InvalidAlgorithmParameterException
{
@@ -57,9 +56,10 @@ public static byte[] decrypt(PrivateKey privateKey, byte[] encrypted)
System.arraycopy(encrypted, 0, encryptedAesKey, 0, ENCRYPTED_AES_KEY_LENGTH);
System.arraycopy(encrypted, ENCRYPTED_AES_KEY_LENGTH, encryptedData, 0,
encrypted.length - ENCRYPTED_AES_KEY_LENGTH);
+ byte[] aad = getAad(sendingOrganizationIdentifier, receivingOrganizationIdentifier);
SecretKey key = decryptRsa(encryptedAesKey, privateKey);
- return AesGcmUtil.decrypt(encryptedData, AAD, key);
+ return AesGcmUtil.decrypt(encryptedData, aad, key);
}
public static KeyPair generateRsa4096KeyPair() throws NoSuchAlgorithmException
@@ -89,4 +89,9 @@ private static SecretKey decryptRsa(byte[] encryptedKey, PrivateKey privateKey)
return new SecretKeySpec(decrypted, "AES");
}
+
+ private static byte[] getAad(String sendingOrganizationIdentifier, String receivingOrganizationIdentifier)
+ {
+ return (sendingOrganizationIdentifier + "|" + receivingOrganizationIdentifier).getBytes(StandardCharsets.UTF_8);
+ }
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java
index 84e40a4..b94a8cf 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java
@@ -38,4 +38,4 @@ protected Stream getAdditionalInputParameters(DelegateExecut
return Stream.of(parameterComponent);
}
-}
+}
\ No newline at end of file
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java
new file mode 100644
index 0000000..a19e4ee
--- /dev/null
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java
@@ -0,0 +1,91 @@
+package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
+
+import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BINARY;
+import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET;
+import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE;
+import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER;
+import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
+import static org.hl7.fhir.r4.model.Bundle.BundleType.TRANSACTION;
+import static org.hl7.fhir.r4.model.DocumentReference.ReferredDocumentStatus.FINAL;
+import static org.hl7.fhir.r4.model.Enumerations.DocumentReferenceStatus.CURRENT;
+
+import java.util.Objects;
+import java.util.UUID;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
+import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper;
+import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
+import org.highmed.dsf.fhir.organization.OrganizationProvider;
+import org.highmed.dsf.fhir.task.TaskHelper;
+import org.highmed.dsf.fhir.variables.FhirResourceValues;
+import org.hl7.fhir.r4.model.Binary;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.DocumentReference;
+import org.hl7.fhir.r4.model.ResourceType;
+import org.springframework.beans.factory.InitializingBean;
+
+import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper;
+
+public class CreateBundle extends AbstractServiceDelegate implements InitializingBean
+{
+ private final OrganizationProvider organizationProvider;
+
+ public CreateBundle(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+
+ this.organizationProvider = organizationProvider;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(organizationProvider, "organizationProvider");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution)
+ {
+ String projectIdentifier = (String) execution.getVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER);
+ DocumentReference documentReference = (DocumentReference) execution
+ .getVariable(BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE);
+ Binary binary = (Binary) execution.getVariable(BPMN_EXECUTION_VARIABLE_BINARY);
+
+ Bundle bundle = createTransactionBundle(projectIdentifier, documentReference, binary);
+
+ LoggingHelper.logDebugBundle("Created Bundle", bundle);
+
+ execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundle));
+ }
+
+ private Bundle createTransactionBundle(String projectIdentifier, DocumentReference documentReference, Binary binary)
+ {
+ Binary binaryToTransmit = new Binary().setContentType(binary.getContentType());
+ binaryToTransmit.setContent(binary.getContent());
+ binaryToTransmit.setId(UUID.randomUUID().toString());
+
+ DocumentReference documentReferenceToTransmit = new DocumentReference().setStatus(CURRENT).setDocStatus(FINAL);
+ documentReferenceToTransmit.getMasterIdentifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER)
+ .setValue(projectIdentifier);
+ documentReferenceToTransmit.addAuthor().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER)
+ .setValue(organizationProvider.getLocalIdentifierValue());
+ documentReferenceToTransmit.setDate(documentReference.getDate());
+ documentReferenceToTransmit.addContent().getAttachment().setContentType(binary.getContentType())
+ .setUrl("urn:uuid:" + binaryToTransmit.getId());
+
+ Bundle bundle = new Bundle().setType(TRANSACTION);
+ bundle.addEntry().setResource(documentReferenceToTransmit)
+ .setFullUrl("urn:uuid:" + documentReferenceToTransmit.getId()).getRequest()
+ .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.DocumentReference.name());
+ bundle.addEntry().setResource(binaryToTransmit).setFullUrl("urn:uuid:" + binaryToTransmit.getId()).getRequest()
+ .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Binary.name());
+
+ return bundle;
+ }
+}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java
index 605819a..9efdc7a 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java
@@ -11,28 +11,29 @@
import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper;
import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
+import org.highmed.dsf.fhir.organization.OrganizationProvider;
import org.highmed.dsf.fhir.task.TaskHelper;
import org.highmed.dsf.fhir.variables.FhirResourceValues;
import org.hl7.fhir.r4.model.Bundle;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.hl7.fhir.r4.model.Reference;
import org.springframework.beans.factory.InitializingBean;
import ca.uhn.fhir.context.FhirContext;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto.KeyProvider;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto.RsaAesGcmUtil;
+import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper;
public class DecryptData extends AbstractServiceDelegate implements InitializingBean
{
- private static final Logger logger = LoggerFactory.getLogger(DecryptData.class);
-
+ private final OrganizationProvider organizationProvider;
private final KeyProvider keyProvider;
public DecryptData(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
- ReadAccessHelper readAccessHelper, KeyProvider keyProvider)
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, KeyProvider keyProvider)
{
super(clientProvider, taskHelper, readAccessHelper);
+ this.organizationProvider = organizationProvider;
this.keyProvider = keyProvider;
}
@@ -41,6 +42,7 @@ public void afterPropertiesSet() throws Exception
{
super.afterPropertiesSet();
+ Objects.requireNonNull(organizationProvider, "organizationProvider");
Objects.requireNonNull(keyProvider, "keyProvider");
}
@@ -48,26 +50,40 @@ public void afterPropertiesSet() throws Exception
protected void doExecute(DelegateExecution execution)
{
byte[] bundleEncrypted = (byte[]) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED);
+ String localOrganizationIdentifier = organizationProvider.getLocalIdentifierValue();
+ String sendingOrganizationIdentifier = getSendingOrganizationIdentifier();
+
+ Bundle bundleDecrypted = decryptBundle(keyProvider.getPrivateKey(), bundleEncrypted,
+ sendingOrganizationIdentifier, localOrganizationIdentifier);
- Bundle bundleDecrypted = decryptBundle(keyProvider.getPrivateKey(), bundleEncrypted);
- logger.debug("Decrypted Bundle: {}",
- FhirContext.forR4().newXmlParser().encodeResourceToString(bundleDecrypted));
+ LoggingHelper.logDebugBundle("Decrypted Bundle", bundleDecrypted);
execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundleDecrypted));
}
- private Bundle decryptBundle(PrivateKey privateKey, byte[] bundleEncrypted)
+ private String getSendingOrganizationIdentifier()
+ {
+ Reference requester = getLeadingTaskFromExecutionVariables().getRequester();
+
+ if (requester.hasIdentifier() && requester.getIdentifier().hasValue())
+ return requester.getIdentifier().getValue();
+ else
+ throw new IllegalArgumentException("Task is missing requester identifier");
+ }
+
+ private Bundle decryptBundle(PrivateKey privateKey, byte[] bundleEncrypted, String sendingOrganizationIdentifier,
+ String receivingOrganizationIdentifier)
{
try
{
- byte[] bundleDecrypted = RsaAesGcmUtil.decrypt(privateKey, bundleEncrypted);
+ byte[] bundleDecrypted = RsaAesGcmUtil.decrypt(privateKey, bundleEncrypted, sendingOrganizationIdentifier,
+ receivingOrganizationIdentifier);
String bundleString = new String(bundleDecrypted, StandardCharsets.UTF_8);
return (Bundle) FhirContext.forR4().newXmlParser().parseResource(bundleString);
}
catch (Exception exception)
{
String taskId = getLeadingTaskFromExecutionVariables().getId();
- logger.warn("Could not decrypt received data-set for task with id='{}'", taskId);
throw new RuntimeException("Could not decrypt received data-set for task with id='" + taskId + "'");
}
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DeleteData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DeleteData.java
index 0222b4e..adaf03b 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DeleteData.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DeleteData.java
@@ -31,7 +31,8 @@ protected void doExecute(DelegateExecution execution)
IdType binaryId = new IdType((String) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE));
logger.info(
- "Permanently deleting Binary with id='{}' provided for project-identifier='{}' referenced in Task with id='{}'...",
+ "Permanently deleting encrypted Binary with id='{}' provided for project-identifier='{}' "
+ + "referenced in Task with id='{}'...",
binaryId.getValue(), projectIdentifier, getLeadingTaskFromExecutionVariables().getId());
deletePermanently(binaryId);
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DownloadData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DownloadData.java
index 1b7fd98..db3ef78 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DownloadData.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DownloadData.java
@@ -56,7 +56,7 @@ private IdType getDataSetReference(Task task)
throw new IllegalArgumentException("No data-set reference present in task with id='" + task.getId() + "'");
if (dataSetReferences.size() > 1)
- logger.warn("Found > 1 data-set references ({}) in task with id='{}', using only the first",
+ logger.warn("Found {} data-set references in task with id='{}', using only the first",
dataSetReferences.size(), task.getId());
return new IdType(dataSetReferences.get(0));
@@ -72,11 +72,10 @@ private byte[] readDataSet(IdType dataSetReference)
{
return binary.readAllBytes();
}
- catch (Exception excpetion)
+ catch (Exception exception)
{
- logger.warn("Downloading Binary with id='{}' failed", dataSetReference.getValue());
throw new RuntimeException("Downloading Binary with id='" + dataSetReference.getValue() + "' failed.",
- excpetion);
+ exception);
}
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java
index ea8bc60..97ce0a5 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java
@@ -19,12 +19,14 @@
import java.util.Map;
import java.util.Objects;
+import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper;
import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
import org.highmed.dsf.fhir.organization.EndpointProvider;
+import org.highmed.dsf.fhir.organization.OrganizationProvider;
import org.highmed.dsf.fhir.task.TaskHelper;
import org.hl7.fhir.r4.model.Attachment;
import org.hl7.fhir.r4.model.Binary;
@@ -42,13 +44,16 @@ public class EncryptData extends AbstractServiceDelegate implements Initializing
{
private static final Logger logger = LoggerFactory.getLogger(EncryptData.class);
+ private final OrganizationProvider organizationProvider;
private final EndpointProvider endpointProvider;
public EncryptData(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
- ReadAccessHelper readAccessHelper, EndpointProvider endpointProvider)
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider,
+ EndpointProvider endpointProvider)
{
super(clientProvider, taskHelper, readAccessHelper);
+ this.organizationProvider = organizationProvider;
this.endpointProvider = endpointProvider;
}
@@ -57,6 +62,7 @@ public void afterPropertiesSet() throws Exception
{
super.afterPropertiesSet();
+ Objects.requireNonNull(organizationProvider, "organizationProvider");
Objects.requireNonNull(endpointProvider, "endpointProvider");
}
@@ -65,10 +71,12 @@ protected void doExecute(DelegateExecution execution)
{
String coordinatingSiteIdentifier = (String) execution
.getVariable(BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER);
+ String localOrganizationIdentifier = organizationProvider.getLocalIdentifierValue();
+
Bundle toEncrypt = (Bundle) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET);
PublicKey publicKey = readPublicKey(coordinatingSiteIdentifier);
- byte[] encrypted = encrypt(publicKey, toEncrypt);
+ byte[] encrypted = encrypt(publicKey, toEncrypt, localOrganizationIdentifier, coordinatingSiteIdentifier);
execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED, encrypted);
}
@@ -117,8 +125,8 @@ private DocumentReference getDocumentReference(Bundle bundle)
"Could not find any DocumentReference in PublicKey Bundle with id='" + bundle.getId() + "'");
if (documentReferences.size() > 1)
- logger.warn("Found > 1 DocumentReferences ({}) in PublicKey Bundle with id='{}'", documentReferences.size(),
- bundle.getId());
+ logger.warn("Found {} DocumentReferences in PublicKey Bundle with id='{}', using the first",
+ documentReferences.size(), bundle.getId());
return documentReferences.get(0);
}
@@ -133,7 +141,8 @@ private Binary getBinary(Bundle bundle)
"Could not find any Binary in PublicKey Bundle with id='" + bundle.getId() + "'");
if (binaries.size() > 1)
- logger.warn("Found > 1 Binaries ({}) in PublicKey Bundle with id='{}'", binaries.size(), bundle.getId());
+ logger.warn("Found {} Binaries in PublicKey Bundle with id='{}', using the first", binaries.size(),
+ bundle.getId());
return binaries.get(0);
}
@@ -146,9 +155,8 @@ private PublicKey getPublicKey(Binary binary, String publicKeyBundleId)
}
catch (Exception exception)
{
- logger.info("Could not generate PublicKey from Binary in PublicKey Bundle with id='{}'", publicKeyBundleId);
throw new RuntimeException(
- "Could not generate PublicKey from Binary in PublicKey Bundle with id='" + publicKeyBundleId + "'",
+ "Could not read PublicKey from Binary in PublicKey Bundle with id='" + publicKeyBundleId + "'",
exception);
}
}
@@ -161,57 +169,37 @@ private void checkHash(DocumentReference documentReference, PublicKey publicKey,
.map(Attachment::getHash).count();
if (numberOfHashes < 1)
- {
throw new RuntimeException(
"Could not find any sha256-hash in DocumentReference from Bundle with id='" + bundleId + "'");
- }
if (numberOfHashes > 1)
- {
- logger.warn("DocumentReference contains > 1 sha256-hashes ({}), using the first from Bundle with id='{}'",
+ logger.warn("DocumentReference contains {} sha256-hashes, using the first from Bundle with id='{}'",
numberOfHashes, bundleId);
- }
byte[] documentReferenceHash = documentReference.getContentFirstRep().getAttachment().getHash();
byte[] publicKeyHash = DigestUtils.sha256(publicKey.getEncoded());
logger.debug("DocumentReference PublicKey sha256-hash='{}' from Bundle with id='{}'",
- byteToHex(documentReferenceHash), bundleId);
- logger.debug("PublicKey actual sha256-hash='{}' from Bundle with id='{}'", byteToHex(publicKeyHash), bundleId);
+ Hex.encodeHexString(documentReferenceHash), bundleId);
+ logger.debug("PublicKey actual sha256-hash='{}' from Bundle with id='{}'", Hex.encodeHexString(publicKeyHash),
+ bundleId);
if (!Arrays.equals(documentReferenceHash, publicKeyHash))
- {
throw new RuntimeException(
"Sha256-hash in DocumentReference does not match computed sha256-hash of Binary in Bundle with id='"
+ bundleId + "'");
- }
- }
-
- private String byteToHex(byte[] toConvert)
- {
- StringBuilder hexString = new StringBuilder(2 * toConvert.length);
-
- for (byte b : toConvert)
- {
- String hex = Integer.toHexString(0xff & b);
- if (hex.length() == 1)
- {
- hexString.append('0');
- }
- hexString.append(hex);
- }
-
- return hexString.toString();
}
- private byte[] encrypt(PublicKey publicKey, Bundle bundle)
+ private byte[] encrypt(PublicKey publicKey, Bundle bundle, String sendingOrganizationIdentifier,
+ String receivingOrganizationIdentifier)
{
try
{
byte[] toEncrypt = FhirContext.forR4().newXmlParser().encodeResourceToString(bundle)
.getBytes(StandardCharsets.UTF_8);
- return RsaAesGcmUtil.encrypt(publicKey, toEncrypt);
+ return RsaAesGcmUtil.encrypt(publicKey, toEncrypt, sendingOrganizationIdentifier,
+ receivingOrganizationIdentifier);
}
catch (Exception exception)
{
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java
index 204eba8..2b406fa 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java
@@ -21,16 +21,20 @@
import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
import org.highmed.dsf.fhir.task.TaskHelper;
import org.highmed.dsf.fhir.variables.FhirResourceValues;
+import org.hl7.fhir.r4.model.Attachment;
import org.hl7.fhir.r4.model.Binary;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.DocumentReference;
-import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Identifier;
+import org.hl7.fhir.r4.model.ResourceType;
import org.hl7.fhir.r4.model.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ca.uhn.fhir.context.FhirContext;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.KdsClientFactory;
+import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper;
public class ReadData extends AbstractServiceDelegate
{
@@ -65,11 +69,10 @@ protected void doExecute(DelegateExecution execution)
String coordinatingSiteIdentifier = getCoordinatingSiteIdentifier(task);
DocumentReference documentReference = readDocumentReference(projectIdentifier, task.getId());
- logger.debug("Read DocumentReference: {}",
- FhirContext.forR4().newXmlParser().encodeResourceToString(documentReference));
+ LoggingHelper.logDebugResource("Read DocumentReference", documentReference);
Binary binary = readBinary(documentReference, task.getId());
- logger.debug("Read Binary: {}", FhirContext.forR4().newXmlParser().encodeResourceToString(binary));
+ LoggingHelper.logDebugBinary("Read Binary", binary);
execution.setVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER, projectIdentifier);
execution.setVariable(BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER, coordinatingSiteIdentifier);
@@ -79,19 +82,20 @@ protected void doExecute(DelegateExecution execution)
private String getProjectIdentifier(Task task)
{
- List identifiers = getTaskHelper()
- .getInputParameterReferenceValues(task, CODESYSTEM_MII_DATA_TRANSFER,
- CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER)
- .filter(Reference::hasIdentifier)
- .filter(i -> NAMINGSYSTEM_MII_PROJECT_IDENTIFIER.equals(i.getIdentifier().getSystem()))
- .map(i -> i.getIdentifier().getValue()).collect(toList());
+ List identifiers = task.getInput().stream()
+ .filter(i -> i.getType().getCoding().stream()
+ .anyMatch(c -> CODESYSTEM_MII_DATA_TRANSFER.equals(c.getSystem())
+ && CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER.equals(c.getCode())))
+ .filter(i -> i.getValue() instanceof Identifier).map(i -> (Identifier) i.getValue())
+ .filter(i -> NAMINGSYSTEM_MII_PROJECT_IDENTIFIER.equals(i.getSystem())).map(Identifier::getValue)
+ .collect(toList());
if (identifiers.size() < 1)
throw new IllegalArgumentException("No project identifier present in task with id='" + task.getId() + "'");
if (identifiers.size() > 1)
- logger.warn("Found > 1 project identifiers ({}) in task with id='{}', using only the first",
- identifiers.size(), task.getId());
+ logger.warn("Found {} project identifiers in task with id='{}', using only the first", identifiers.size(),
+ task.getId());
return identifiers.get(0);
}
@@ -119,28 +123,54 @@ private DocumentReference readDocumentReference(String projectIdentifier, String
if (documentReferences.size() > 1)
logger.warn(
- "Found > 1 DocumentReferences ({}) for project-identifier='{}' referenced in task with id='{}', using only the first",
- documentReferences.size(), projectIdentifier, taskId);
+ "Found {} DocumentReferences for project-identifier='{}' referenced in task with id='{}', using first ({})",
+ documentReferences.size(), projectIdentifier, taskId,
+ documentReferences.get(0).getIdElement().getValue());
return documentReferences.get(0);
}
private Binary readBinary(DocumentReference documentReference, String taskId)
{
- List binaries = Stream.of(documentReference).filter(DocumentReference::hasContent)
- .flatMap(dr -> dr.getContent().stream()).map(c -> c.getAttachment().getUrl()).map(this::readBinary)
- .collect(toList());
-
- if (binaries.size() < 1)
- throw new IllegalArgumentException("Could not find any Binary from DocumentReference with id='"
+ List urls = Stream.of(documentReference).filter(DocumentReference::hasContent)
+ .flatMap(dr -> dr.getContent().stream())
+ .filter(DocumentReference.DocumentReferenceContentComponent::hasAttachment)
+ .map(DocumentReference.DocumentReferenceContentComponent::getAttachment).filter(Attachment::hasUrl)
+ .map(Attachment::getUrl).collect(toList());
+
+ if (urls.size() < 1)
+ throw new IllegalArgumentException("Could not find any attachment URLs in DocumentReference with id='"
+ documentReference.getId() + "' belonging to task with id='" + taskId + "'");
- if (binaries.size() > 1)
+ if (urls.size() > 1)
+ logger.warn(
+ "Found {} attachment URLs in DocumentReference with id='{}' belonging to task with id='{}', using first ({})",
+ urls.size(), documentReference.getId(), taskId, urls.get(0));
+
+ if (!validBinaryUrl(urls.get(0)))
+ {
logger.warn(
- "Found > 1 Binaries ({}) from DocumentReference with id='{}' belonging to task with id='{}', using only the first",
- binaries.size(), documentReference.getId(), taskId);
+ "Attachment URL {} in DocumentReference with id='{}' belonging to task with id='{}', not a valid Binary reference,"
+ + " should be a relative Binary reference or an absolute Binary reference to KDS FHIR server at {}",
+ urls.get(0), documentReference.getId(), taskId, kdsClientFactory.getKdsClient().getFhirBaseUrl());
+ throw new IllegalArgumentException(
+ "Attachment URL " + urls.get(0) + " in DocumentReference with id='" + documentReference.getId()
+ + "' belonging to task with id='" + taskId + "' not a valid Binary reference");
+ }
+
+ return readBinary(urls.get(0));
+ }
+
+ private boolean validBinaryUrl(String url)
+ {
+ IdType idType = new IdType(url);
+ String fhirBaseUrl = kdsClientFactory.getKdsClient().getFhirBaseUrl();
+
+ // expecting no Base URL or, Base URL equal to KDS client Base URL
+ boolean hasValidBaseUrl = !idType.hasBaseUrl() || fhirBaseUrl.equals(idType.getBaseUrl());
+ boolean isBinaryReference = ResourceType.Binary.name().equals(idType.getResourceType());
- return binaries.get(0);
+ return hasValidBaseUrl && isBinaryReference;
}
private Binary readBinary(String url)
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/StoreData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/StoreData.java
index 4e63926..99624ac 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/StoreData.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/StoreData.java
@@ -29,7 +29,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper;
public class StoreData extends AbstractServiceDelegate
{
@@ -81,8 +81,7 @@ private Binary createBinary(byte[] content, String coordinatingSiteIdentifier)
Binary binary = new Binary().setContentType(MediaType.APPLICATION_OCTET_STREAM)
.setSecurityContext(securityContext).setData(content);
- logger.debug("Created Binary: {}",
- FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(binary));
+ LoggingHelper.logDebugBinary("Created Binary", binary);
return binary;
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java
index 1f3309a..91edf38 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java
@@ -20,6 +20,8 @@
import org.hl7.fhir.r4.model.Reference;
import org.springframework.beans.factory.InitializingBean;
+import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.MimeTypeHelper;
+
public class ValidateDataCos extends AbstractServiceDelegate implements InitializingBean
{
public ValidateDataCos(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
@@ -74,10 +76,17 @@ protected void doExecute(DelegateExecution execution)
throw new RuntimeException("DocumentReference contains < 1 or > 1 of projectIdentifiers (" + countMi + ")");
}
- long countB = entries.stream().filter(e -> e.getResource() instanceof Binary).count();
+ List binaries = entries.stream().map(Bundle.BundleEntryComponent::getResource)
+ .filter(r -> r instanceof Binary).map(r -> (Binary) r).collect(toList());
+
+ long countB = binaries.size();
if (countB != 1)
{
throw new RuntimeException("Bundle contains < 1 or > 1 of Binaries (" + countB + ")");
}
+
+ byte[] dataB = binaries.get(0).getData();
+ String mimeTypeB = binaries.get(0).getContentType();
+ MimeTypeHelper.validate(dataB, mimeTypeB);
}
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java
index 9cb0e3b..eab4184 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java
@@ -1,17 +1,8 @@
package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BINARY;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER;
-import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
-import static org.hl7.fhir.r4.model.Bundle.BundleType.TRANSACTION;
-import static org.hl7.fhir.r4.model.DocumentReference.ReferredDocumentStatus.FINAL;
-import static org.hl7.fhir.r4.model.Enumerations.DocumentReferenceStatus.CURRENT;
import java.util.Objects;
-import java.util.UUID;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
@@ -19,21 +10,13 @@
import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
import org.highmed.dsf.fhir.organization.OrganizationProvider;
import org.highmed.dsf.fhir.task.TaskHelper;
-import org.highmed.dsf.fhir.variables.FhirResourceValues;
import org.hl7.fhir.r4.model.Binary;
-import org.hl7.fhir.r4.model.Bundle;
-import org.hl7.fhir.r4.model.DocumentReference;
-import org.hl7.fhir.r4.model.ResourceType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
-import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.MimeTypeHelper;
public class ValidateDataDic extends AbstractServiceDelegate implements InitializingBean
{
- private static final Logger logger = LoggerFactory.getLogger(ValidateDataDic.class);
-
private final OrganizationProvider organizationProvider;
public ValidateDataDic(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
@@ -55,40 +38,11 @@ public void afterPropertiesSet() throws Exception
@Override
protected void doExecute(DelegateExecution execution)
{
- String projectIdentifier = (String) execution.getVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER);
- DocumentReference documentReference = (DocumentReference) execution
- .getVariable(BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE);
Binary binary = (Binary) execution.getVariable(BPMN_EXECUTION_VARIABLE_BINARY);
- Bundle bundle = createTransactionBundle(projectIdentifier, documentReference, binary);
- logger.debug("Created Bundle: {}", FhirContext.forR4().newXmlParser().encodeResourceToString(bundle));
-
- execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundle));
- }
-
- private Bundle createTransactionBundle(String projectIdentifier, DocumentReference documentReference, Binary binary)
- {
- Binary binaryToTransmit = new Binary().setContentType(binary.getContentType());
- binaryToTransmit.setContent(binary.getContent());
- binaryToTransmit.setId(UUID.randomUUID().toString());
-
- DocumentReference documentReferenceToTransmit = new DocumentReference().setStatus(CURRENT).setDocStatus(FINAL);
- documentReferenceToTransmit.getMasterIdentifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER)
- .setValue(projectIdentifier);
- documentReferenceToTransmit.addAuthor().setType(ResourceType.Organization.name()).getIdentifier()
- .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER)
- .setValue(organizationProvider.getLocalIdentifierValue());
- documentReferenceToTransmit.setDate(documentReference.getDate());
- documentReferenceToTransmit.addContent().getAttachment().setContentType(binary.getContentType())
- .setUrl("urn:uuid:" + binaryToTransmit.getId());
-
- Bundle bundle = new Bundle().setType(TRANSACTION);
- bundle.addEntry().setResource(documentReferenceToTransmit)
- .setFullUrl("urn:uuid:" + documentReferenceToTransmit.getId()).getRequest()
- .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.DocumentReference.name());
- bundle.addEntry().setResource(binaryToTransmit).setFullUrl("urn:uuid:" + binaryToTransmit.getId()).getRequest()
- .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Binary.name());
+ String mimeTypeBinary = binary.getContentType();
+ byte[] dataBinary = binary.getData();
- return bundle;
+ MimeTypeHelper.validate(dataBinary, mimeTypeBinary);
}
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java
index 6eb62bf..b9cf338 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java
@@ -21,6 +21,7 @@
import de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto.KeyProvider;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto.KeyProviderImpl;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.message.StartReceiveProcess;
+import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.CreateBundle;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.DecryptData;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.DeleteData;
import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.DownloadData;
@@ -52,75 +53,77 @@ public class TransferDataConfig
@Autowired
private FhirContext fhirContext;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASE_URL", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = true, description = "The base address of the KDS FHIR server to read/store FHIR resources", recommendation = "None", example = "http://foo.bar/fhir")
+ @Documentation(required = true, description = "The base address of the KDS FHIR server to read/store FHIR resources", recommendation = "None", example = "http://foo.bar/fhir")
@Value("${de.medizininformatik.initiative.kds.fhir.server.base.url:#{null}}")
private String fhirStoreBaseUrl;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_CLIENT", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Client implementation used to connect to the KDS FHIR server in order to read/store FHIR resources", recommendation = "Use default value", example = "None")
+ @Documentation(description = "Client implementation used to connect to the KDS FHIR server in order to read/store FHIR resources", recommendation = "Use default value", example = "None")
@Value("${de.medizininformatik.initiative.kds.fhir.server.client:de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir.KdsFhirClientImpl}")
private String fhirStoreClientClass;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_TRUST_CERTIFICATES", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "PEM encoded file with one or more trusted root certificate to validate the KDS FHIR server certificate when connecting via https", recommendation = "Use docker secret file to configure", example = "/run/secrets/hospital_ca.pem")
+ @Documentation(description = "PEM encoded file with one or more trusted root certificate to validate the KDS FHIR server certificate when connecting via https", recommendation = "Use docker secret file to configure", example = "/run/secrets/hospital_ca.pem")
@Value("${de.medizininformatik.initiative.kds.fhir.server.trust.certificates:#{null}}")
private String fhirStoreTrustStore;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_CERTIFICATE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "PEM encoded file with client-certificate, if KDS FHIR server requires mutual TLS authentication", recommendation = "Use docker secret file to configure", example = "/run/secrets/kds_server_client_certificate.pem")
+ @Documentation(description = "PEM encoded file with client-certificate, if KDS FHIR server requires mutual TLS authentication", recommendation = "Use docker secret file to configure", example = "/run/secrets/kds_server_client_certificate.pem")
@Value("${de.medizininformatik.initiative.kds.fhir.server.certificate:#{null}}")
private String fhirStoreCertificate;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Private key corresponding to the KDS FHIR server client-certificate as PEM encoded file. Use *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD* or *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE* if private key is encrypted", recommendation = "Use docker secret file to configure", example = "/run/secrets/kds_server_private_key.pem")
+ @Documentation(description = "Private key corresponding to the KDS FHIR server client-certificate as PEM encoded file. Use *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD* or *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE* if private key is encrypted", recommendation = "Use docker secret file to configure", example = "/run/secrets/kds_server_private_key.pem")
@Value("${de.medizininformatik.initiative.kds.fhir.server.private.key:#{null}}")
private String fhirStorePrivateKey;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD or DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Password to decrypt the KDS FHIR server client-certificate encrypted private key", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "/run/secrets/kds_server_private_key.pem.password")
+ @Documentation(filePropertySupported = true, description = "Password to decrypt the KDS FHIR server client-certificate encrypted private key", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "/run/secrets/kds_server_private_key.pem.password")
@Value("${de.medizininformatik.initiative.kds.fhir.server.private.key.password:#{null}}")
private char[] fhirStorePrivateKeyPassword;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_USERNAME", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Basic authentication username, set if the server containing the FHIR KDS data requests authentication using basic auth", recommendation = "None", example = "None")
+ @Documentation(description = "Basic authentication username, set if the server containing the FHIR KDS data requests authentication using basic auth", recommendation = "None", example = "None")
@Value("${de.medizininformatik.initiative.kds.fhir.server.basicauth.username:#{null}}")
private String fhirStoreUsername;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_PASSWORD or DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_PASSWORD_FILE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Basic authentication password, set if the server containing the FHIR KDS data requests authentication using basic auth", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "/run/secrets/kds_server_basicauth.password")
+ @Documentation(filePropertySupported = true, description = "Basic authentication password, set if the server containing the FHIR KDS data requests authentication using basic auth", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "/run/secrets/kds_server_basicauth.password")
@Value("${de.medizininformatik.initiative.kds.fhir.server.basicauth.password:#{null}}")
private String fhirStorePassword;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BEARER_TOKEN", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Bearer token for authentication, set if the server containing the FHIR KDS data requests authentication using a bearer token, cannot be set using docker secrets", recommendation = "None", example = "None")
+ @Documentation(description = "Bearer token for authentication, set if the server containing the FHIR KDS data requests authentication using a bearer token, cannot be set using docker secrets", recommendation = "None", example = "None")
@Value("${de.medizininformatik.initiative.kds.fhir.server.bearer.token:#{null}}")
private String fhirStoreBearerToken;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_TIMEOUT_CONNECT", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "The timeout in milliseconds until a connection is established between the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value")
+ @Documentation(description = "The timeout in milliseconds until a connection is established between the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value")
@Value("${de.medizininformatik.initiative.kds.fhir.server.timeout.connect:10000}")
private int fhirStoreConnectTimeout;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_TIMEOUT_CONNECTION_REQUEST", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "The timeout in milliseconds used when requesting a connection from the connection manager between the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value")
+ @Documentation(description = "The timeout in milliseconds used when requesting a connection from the connection manager between the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value")
@Value("${de.medizininformatik.initiative.kds.fhir.server.timeout.connection.request:10000}")
private int fhirStoreConnectionRequestTimeout;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_TIMEOUT_SOCKET", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Maximum period of inactivity in milliseconds between two consecutive data packets of the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value")
+ @Documentation(description = "Maximum period of inactivity in milliseconds between two consecutive data packets of the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value")
@Value("${de.medizininformatik.initiative.kds.fhir.server.timeout.socket:10000}")
private int fhirStoreSocketTimeout;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_CLIENT_VERBOSE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "The KDS client will log additional debug output", recommendation = "Change default value only if exceptions occur", example = "See default value")
+ @Documentation(description = "The KDS client will log additional debug output", recommendation = "Change default value only if exceptions occur", example = "See default value")
@Value("${de.medizininformatik.initiative.kds.fhir.server.client.verbose:false}")
private boolean fhirStoreHapiClientVerbose;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_URL", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Proxy location, set if the server containing the FHIR KDS data can only be reached through a proxy", recommendation = "None", example = "http://proxy.foo:8080")
+ @Documentation(description = "Proxy location, set if the server containing the FHIR KDS data can only be reached through a proxy", recommendation = "None", example = "http://proxy.foo:8080")
@Value("${de.medizininformatik.initiative.kds.fhir.server.proxy.url:#{null}}")
private String fhirStoreProxyUrl;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_USERNAME", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Proxy username, set if the server containing the FHIR KDS data can only be reached through a proxy which requests authentication", recommendation = "None", example = "None")
+ @Documentation(description = "Proxy username, set if the server containing the FHIR KDS data can only be reached through a proxy which requests authentication", recommendation = "None", example = "None")
@Value("${de.medizininformatik.initiative.kds.fhir.server.proxy.username:#{null}}")
private String fhirStoreProxyUsername;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_PASSWORD or DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_PASSWORD_FILE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Proxy password, set if the server containing the FHIR KDS data can only be reached through a proxy which requests authentication", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "None")
+ @Documentation(filePropertySupported = true, description = "Proxy password, set if the server containing the FHIR KDS data can only be reached through a proxy which requests authentication", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "None")
@Value("${de.medizininformatik.initiative.kds.fhir.server.proxy.password:#{null}}")
private String fhirStoreProxyPassword;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_COS_PRIVATE_KEY", processNames = "medizininformatik-initiativede_dataReceive/", required = true, description = "Location of the COS private-key as 4096 Bit RSA PEM encoded, not encrypted file", recommendation = "Use docker secret file to configure", example = "/run/secrets/cos_private_key.pem")
+ @Documentation(required = true, processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "Location of the COS private-key as 4096 Bit RSA PEM encoded, not encrypted file", recommendation = "Use docker secret file to configure", example = "/run/secrets/cos_private_key.pem")
@Value("${de.medizininformatik.initiative.cos.private.key:#{null}}")
private String cosPrivateKeyFile;
- @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_COS_PUBLIC_KEY", processNames = "medizininformatik-initiativede_dataReceive/", required = true, description = "Location of the COS public-key as 4096 Bit RSA PEM encoded file", recommendation = "Use docker secret file to configure", example = "/run/secrets/cos_public_key.pem")
+ @Documentation(required = true, processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "Location of the COS public-key as 4096 Bit RSA PEM encoded file", recommendation = "Use docker secret file to configure", example = "/run/secrets/cos_public_key.pem")
@Value("${de.medizininformatik.initiative.cos.public.key:#{null}}")
private String cosPublicKeyFile;
@@ -129,7 +132,7 @@ public class TransferDataConfig
@Bean
@SuppressWarnings("unchecked")
- public KdsClientFactory projectathonClientFactory()
+ public KdsClientFactory kdsClientFactory()
{
Path trustStorePath = checkExists(fhirStoreTrustStore);
Path certificatePath = checkExists(fhirStoreCertificate);
@@ -164,12 +167,12 @@ private Path checkExists(String file)
}
}
- // miiProjectathonDataSend
+ // projectathonDataSend
@Bean
public ReadData readData()
{
- return new ReadData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext, projectathonClientFactory());
+ return new ReadData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext, kdsClientFactory());
}
@Bean
@@ -178,10 +181,17 @@ public ValidateDataDic validateDataDic()
return new ValidateDataDic(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider);
}
+ @Bean
+ public CreateBundle createBundle()
+ {
+ return new CreateBundle(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider);
+ }
+
@Bean
public EncryptData encryptData()
{
- return new EncryptData(fhirClientProvider, taskHelper, readAccessHelper, endpointProvider);
+ return new EncryptData(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider,
+ endpointProvider);
}
@Bean
@@ -203,7 +213,7 @@ public DeleteData deleteData()
return new DeleteData(fhirClientProvider, taskHelper, readAccessHelper);
}
- // miiProjectathonDataReceive
+ // projectathonDataReceive
@Bean
public DownloadData downloadData()
@@ -221,7 +231,7 @@ public KeyProvider keyProvider()
@Bean
public DecryptData decryptData()
{
- return new DecryptData(fhirClientProvider, taskHelper, readAccessHelper, keyProvider());
+ return new DecryptData(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider, keyProvider());
}
@Bean
@@ -233,7 +243,6 @@ public ValidateDataCos validateDataCos()
@Bean
public InsertData insertData()
{
- return new InsertData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext,
- projectathonClientFactory());
+ return new InsertData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext, kdsClientFactory());
}
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/LoggingHelper.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/LoggingHelper.java
new file mode 100644
index 0000000..4bcca76
--- /dev/null
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/LoggingHelper.java
@@ -0,0 +1,50 @@
+package de.medizininformatik_initiative.processes.projectathon.data_transfer.util;
+
+import java.nio.charset.StandardCharsets;
+
+import org.hl7.fhir.r4.model.Binary;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.Resource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ca.uhn.fhir.context.FhirContext;
+
+public class LoggingHelper
+{
+ private static final Logger logger = LoggerFactory.getLogger(LoggingHelper.class);
+
+ public static void logDebugBundle(String message, Bundle bundle)
+ {
+ Bundle copy = bundle.copy();
+
+ // replace actual content with content size in bytes to not leak sensitive information
+ copy.getEntry().stream().filter(Bundle.BundleEntryComponent::hasResource)
+ .map(Bundle.BundleEntryComponent::getResource).filter(r -> r instanceof Binary).map(r -> (Binary) r)
+ .forEach(b -> b.setContent(createReplacementContent(b)));
+
+ logDebugResource(message, copy);
+ }
+
+ public static void logDebugBinary(String message, Binary binary)
+ {
+ Binary copy = binary.copy();
+
+ // replace actual content with content size in bytes to not leak sensitive information
+ copy.setContent(createReplacementContent(copy));
+
+ logDebugResource(message, copy);
+ }
+
+ public static void logDebugResource(String message, Resource resource)
+ {
+ logger.debug(message + ": {}",
+ FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(resource));
+ }
+
+ private static byte[] createReplacementContent(Binary binary)
+ {
+ return ("original content (" + binary.getContent().length + " bytes) replaced")
+ .getBytes(StandardCharsets.UTF_8);
+ }
+}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java
new file mode 100644
index 0000000..432568f
--- /dev/null
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java
@@ -0,0 +1,58 @@
+package de.medizininformatik_initiative.processes.projectathon.data_transfer.util;
+
+import org.apache.tika.config.TikaConfig;
+import org.apache.tika.io.TikaInputStream;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.mime.MediaType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MimeTypeHelper
+{
+ private static final Logger logger = LoggerFactory.getLogger(MimeTypeHelper.class);
+
+ /**
+ * Detects the mime-type of the provided data and validates if the detected mime-type equals the declared mime-type.
+ * Logs a warning if the full mime-types do not match, throws a {@link RuntimeException} if the base mime-types do
+ * not match.
+ *
+ * @param data
+ * of which the mime-type should be detected
+ * @param declared
+ * the declared mime-type of the data
+ * @throws RuntimeException
+ * if the detected and the declared base mime-type do not match
+ */
+ public static void validate(byte[] data, String declared)
+ {
+ MediaType declaredMimeType = MediaType.parse(declared);
+ MediaType detectedMimeType = MediaType.EMPTY;
+
+ try
+ {
+ TikaConfig tika = new TikaConfig();
+ TikaInputStream input = TikaInputStream.get(data);
+ Metadata metadata = new Metadata();
+
+ // gives only a hint to the possible mime-type
+ // this is needed because text/csv cannot be detected without any hint and would resolve to text/plain
+ metadata.add(Metadata.CONTENT_TYPE, declaredMimeType.toString());
+
+ detectedMimeType = tika.getDetector().detect(input, metadata);
+ }
+ catch (Exception exception)
+ {
+ throw new RuntimeException("Could not detect mime-type of binary", exception);
+ }
+
+ if (!declaredMimeType.equals(detectedMimeType))
+ logger.warn("Declared mime-type {} does not match detected mime-type {}", declaredMimeType.toString(),
+ detectedMimeType.toString());
+
+ if (!declaredMimeType.getType().equals(detectedMimeType.getType()))
+ {
+ throw new RuntimeException("Declared base mime-type of '" + declaredMimeType.toString()
+ + "' does not match detected base mime-type of '" + detectedMimeType.toString() + "'");
+ }
+ }
+}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/receive.bpmn b/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/receive.bpmn
index 9d6edbd..a89793b 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/receive.bpmn
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/receive.bpmn
@@ -18,8 +18,8 @@
Flow_1w6vljw
-
-
+
+
Flow_0j6v09z
Flow_1w6vljw
@@ -28,7 +28,7 @@
Flow_1c3t0x1
Flow_0j6v09z
-
+
@@ -71,7 +71,7 @@
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/send.bpmn b/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/send.bpmn
index 7e0618c..7484c77 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/send.bpmn
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/send.bpmn
@@ -1,5 +1,5 @@
-
+
Flow_0kkjyst
@@ -10,14 +10,14 @@
Flow_0yamo5r
-
+
Flow_0yamo5r
Flow_0zrvqk8
- Flow_0zrvqk8
+ Flow_05qlnk4
Flow_15vmy2h
@@ -62,34 +62,39 @@
Flow_1pzxejf
Flow_0phc02z
+
+
+ Flow_0zrvqk8
+ Flow_05qlnk4
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
@@ -99,6 +104,10 @@
+
+
+
+
@@ -112,31 +121,34 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml
index 55d01a5..fe89b80 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml
@@ -85,7 +85,7 @@
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml
index 72956e5..46f707b 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml
@@ -65,7 +65,7 @@
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-cryptography.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-cryptography.xml
index 913c2a2..088591d 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-cryptography.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-cryptography.xml
@@ -13,7 +13,7 @@
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-data-transfer.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-data-transfer.xml
index cfc0686..fb228d5 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-data-transfer.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-data-transfer.xml
@@ -13,7 +13,7 @@
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/NamingSystem/mii-project-identifier.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/NamingSystem/mii-project-identifier.xml
index 12f494d..91af56f 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/NamingSystem/mii-project-identifier.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/NamingSystem/mii-project-identifier.xml
@@ -6,9 +6,10 @@
-
+
+
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-receive.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-receive.xml
index 9b48772..bc58dee 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-receive.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-receive.xml
@@ -6,11 +6,13 @@
+
+
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml
index b995cb1..00d10c5 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml
@@ -6,11 +6,13 @@
+
+
-
+
@@ -120,17 +122,17 @@
-
-
+
-
-
-
+
+
+
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-cryptography.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-cryptography.xml
index 4d38819..e71b1ab 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-cryptography.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-cryptography.xml
@@ -13,7 +13,7 @@
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-data-transfer.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-data-transfer.xml
index f4d2952..221a68f 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-data-transfer.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-data-transfer.xml
@@ -13,7 +13,7 @@
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java
index 5b0ed75..3b4e7f8 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java
@@ -24,8 +24,6 @@
import org.hl7.fhir.r4.model.Task.TaskIntent;
import org.hl7.fhir.r4.model.Task.TaskStatus;
-import ca.uhn.fhir.context.FhirContext;
-
public class DataSendExampleStarter
{
public static void main(String[] args) throws Exception
@@ -60,9 +58,7 @@ private static Task createTask()
.setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER);
task.addInput()
- .setValue(new Reference().setIdentifier(
- new Identifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER).setValue("Test_PROJECT"))
- .setType(ResourceType.DocumentReference.name()))
+ .setValue(new Identifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER).setValue("Test_PROJECT"))
.getType().addCoding().setSystem(CODESYSTEM_MII_DATA_TRANSFER)
.setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER);
diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/TaskProfileTest.java b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/TaskProfileTest.java
index 595a631..5f9f263 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/TaskProfileTest.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/TaskProfileTest.java
@@ -113,9 +113,7 @@ private Task createValidTaskStartDataSend()
.setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER);
task.addInput()
- .setValue(new Reference().setIdentifier(
- new Identifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER).setValue("Test_PROJECT"))
- .setType(ResourceType.DocumentReference.name()))
+ .setValue(new Identifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER).setValue("Test_PROJECT"))
.getType().addCoding().setSystem(CODESYSTEM_MII_DATA_TRANSFER)
.setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER);
diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml
index 542296d..b744708 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml
@@ -17,7 +17,7 @@
-
+
@@ -28,7 +28,7 @@
-
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml
index a5c2365..d85d569 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml
@@ -5,7 +5,7 @@
-
+
@@ -53,12 +53,9 @@
-
-
-
+
-
-
+
\ No newline at end of file
diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_NT-proBNP.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_NT-proBNP.xml
index 7c489c2..3c1d4ee 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_NT-proBNP.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_NT-proBNP.xml
@@ -53,12 +53,9 @@
-
-
-
+
-
-
+
\ No newline at end of file
diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_WE-STORM.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_WE-STORM.xml
index 4b633cd..6b86da1 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_WE-STORM.xml
+++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_WE-STORM.xml
@@ -53,12 +53,9 @@
-
-
-
+
-
-
+
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/README.md b/mii-dsf-processes-docker-test-setup/README.md
index c487e6e..0359884 100644
--- a/mii-dsf-processes-docker-test-setup/README.md
+++ b/mii-dsf-processes-docker-test-setup/README.md
@@ -7,41 +7,51 @@ mvn clean package
```
Add entries to your hosts file
+
```
127.0.0.1 dic
127.0.0.1 cos
```
-*A total of four console windows are required. Start docker-compose commands from sub-folder:* `mii-dsf-processes/mii-dsf-processes-docker-test-setup`
+*A total of five console windows are required. Start docker-compose commands for consoles 1 to 4 from
+sub-folder:* `mii-dsf-processes/mii-dsf-processes-docker-test-setup`
+
+Console 1: Start DIC HAPI FHIR Server
-Console 1: Start DIC HAPI FHIR Server
```sh
docker-compose up dic-fhir-store-hapi
```
+
Access at http://localhost:8080/fhir/
Console 4: Start COS HAPI FHIR Server
+
```sh
docker-compose up cos-fhir-store-hapi
```
+
Access at http://localhost:8081/fhir/
Console 2: Start DIC DSF FHIR Server and wait till started
+
```sh
docker-compose up -d dic-fhir && docker-compose logs -f dic-fhir
```
-Console 2: Disconnect from log output (Ctrl-C) if Server started
-Console 2: Start DIC DSF BPE Server
+
+Console 2: Disconnect from log output (Ctrl-C) if Server started Console 2: Start DIC DSF BPE Server
+
```sh
docker-compose up -d dic-bpe && docker-compose logs -f dic-fhir dic-bpe
````
Console 3: Start COS DSF FHIR Server and wait till started
+
```sh
docker-compose up -d cos-fhir && docker-compose logs -f cos-fhir
```
-Console 3: Disconnect from log output (Ctrl-C) if Server started
-Console 3: Start COS DSF BPE Server
+
+Console 3: Disconnect from log output (Ctrl-C) if Server started Console 3: Start COS DSF BPE Server
+
```sh
docker-compose up -d cos-bpe && docker-compose logs -f cos-fhir cos-bpe
````
@@ -51,31 +61,40 @@ Webbrowser at http://localhost:8080/fhir/: Add Demo Data to DIC HAPI FHIR Server
[DicFhirStore_Demo.xml](../mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml)
-->
-*Start curl commands from root-folder:* `mii-dsf-processes`
+*Start curl commands in console 5 from root-folder:* `mii-dsf-processes`
+
+Console 5: Execute Demo Transaction-Bundle for HAPI
-Console 6: Execute Demo Transaction-Bundle for HAPI
```sh
curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \
-d @mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml \
http://localhost:8080/fhir
```
-Console 6: Start Data Send Process at DIC using the following command
+Console 5: Start Data Send Process at DIC using the following command
+
+*Unfortunately this command does not work on Windows. An alternative for starting the process is using WSL or the
+example starter class with name* `DataSendExampleStarter` *in*
+`mii-dsf-process-projectathon-data-transfer/src/test/java/../bpe/start`
+
```sh
curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \
-d @mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml \
--ssl-no-revoke --cacert mii-dsf-processes-test-data-generator/cert/ca/testca_certificate.pem \
--cert mii-dsf-processes-test-data-generator/cert/Webbrowser_Test_User/Webbrowser_Test_User_certificate.pem \
--key mii-dsf-processes-test-data-generator/cert/Webbrowser_Test_User/Webbrowser_Test_User_private-key.pem \
+--pass password \
https://dic/fhir/Task
```
-Console X: Check data transferred to COS
+Console 5: Check data transferred to COS
+
```sh
curl http://localhost:8081/fhir/DocumentReference
```
-Console X: Stop everything
+Console 5: Stop everything
+
```sh
docker-compose down -v
```
\ No newline at end of file
diff --git a/mii-dsf-processes-documentation-generator/pom.xml b/mii-dsf-processes-documentation-generator/pom.xml
index b2e68be..564f3af 100644
--- a/mii-dsf-processes-documentation-generator/pom.xml
+++ b/mii-dsf-processes-documentation-generator/pom.xml
@@ -9,7 +9,7 @@
de.medizininformatik-initiative
mii-dsf-processes
- 0.1.0-SNAPSHOT
+ 0.1.0-RC1
diff --git a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java
index 268f8ad..d4e8b78 100644
--- a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java
+++ b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java
@@ -9,15 +9,37 @@
@Target(ElementType.FIELD)
public @interface Documentation
{
- String environmentVariables();
+ /**
+ * @return true
if this property is required for processes that are listed in
+ * {@link Documentation#processNames}
+ */
+ boolean required() default false;
- boolean required();
+ /**
+ * @return true
if a docker secret file can be used to configure this property, else
+ * false
, which means that a docker secret file cannot be used to configure this
+ * property
+ */
+ boolean filePropertySupported() default false;
- String processNames();
+ /**
+ * @return an empty array if all processes use this property or an array of length >=1 containing only specific
+ * processes that use this property, but not all
+ */
+ String[] processNames() default {};
+ /**
+ * @return description helping to configure this property
+ */
String description();
+ /**
+ * @return example value helping to configure this property
+ */
String example();
+ /**
+ * @return recommendation helping to configure this property
+ */
String recommendation();
}
diff --git a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/DocumentationGenerator.java b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/DocumentationGenerator.java
index e231877..06dc7f0 100644
--- a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/DocumentationGenerator.java
+++ b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/DocumentationGenerator.java
@@ -1,15 +1,22 @@
package de.medizininformatik_initiative.processes.documentation.generator;
+import static java.util.stream.Collectors.toList;
+
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
-import java.lang.annotation.Annotation;
+import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Optional;
+import org.camunda.bpm.model.bpmn.Bpmn;
+import org.camunda.bpm.model.bpmn.instance.BaseElement;
+import org.camunda.bpm.model.bpmn.instance.Process;
+import org.highmed.dsf.bpe.ProcessPluginDefinition;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper;
@@ -32,57 +39,146 @@ public void execute(String[] args)
Arrays.asList(args).forEach(this::generateDocumentation);
}
- private void generateDocumentation(String configDirectory)
+ private void generateDocumentation(String workingPackage)
{
- String filename = "target/Documentation_" + configDirectory + ".md";
- logger.info("Generating documentation for directory: {} in file: {}", configDirectory, filename);
+ String filename = "target/Documentation_" + workingPackage + ".md";
+ logger.info("Generating documentation for package {} in file {}", workingPackage, filename);
+
+ Reflections reflections = createReflections(workingPackage);
+
+ List pluginProcessNames = getPluginProcessNames(reflections, workingPackage);
+ List fields = getFields(reflections);
- Reflections reflections = createReflections(configDirectory);
- List fields = getFields(reflections, Documentation.class);
- writeFields(fields, filename, configDirectory);
+ writeFields(fields, pluginProcessNames, filename, workingPackage);
}
- private Reflections createReflections(String configDirectory)
+ private Reflections createReflections(String workingPackage)
{
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
- .setUrls(ClasspathHelper.forPackage(configDirectory)).setScanners(Scanners.FieldsAnnotated);
+ .setUrls(ClasspathHelper.forPackage(workingPackage))
+ .setScanners(Scanners.FieldsAnnotated, Scanners.SubTypes);
return new Reflections(configurationBuilder);
}
- private List getFields(Reflections reflections, Class extends Annotation> annotation)
+ private List getPluginProcessNames(Reflections reflections, String workingPackage)
+ {
+ List> pluginDefinitionClasses = new ArrayList<>(
+ reflections.getSubTypesOf(ProcessPluginDefinition.class));
+
+ if (pluginDefinitionClasses.size() < 1)
+ {
+ logger.warn("No ProcessPluginDefinitions found in package {}", workingPackage);
+ return Collections.emptyList();
+ }
+
+ if (pluginDefinitionClasses.size() > 1)
+ logger.warn("Found {} ProcessPluginDefinitions ({}) in package {}, using only the first",
+ pluginDefinitionClasses.size(), pluginDefinitionClasses, workingPackage);
+
+ try
+ {
+ ProcessPluginDefinition processPluginDefinition = pluginDefinitionClasses.get(0).getConstructor()
+ .newInstance();
+
+ return processPluginDefinition.getBpmnFiles().map(this::getProcessName).filter(Optional::isPresent)
+ .map(Optional::get).collect(toList());
+ }
+ catch (Exception exception)
+ {
+ logger.warn(
+ "Could not read process names from package {} and ProcessPluginDefinition with name {}, reason is '{}'",
+ workingPackage, pluginDefinitionClasses.get(0).getName(), exception.getMessage());
+ return Collections.emptyList();
+ }
+ }
+
+ private Optional getProcessName(String bpmnFile)
+ {
+ try
+ {
+ InputStream resource = getClass().getClassLoader().getResource(bpmnFile).openStream();
+ return Bpmn.readModelFromStream(resource).getModelElementsByType(Process.class).stream()
+ .map(BaseElement::getId).findFirst();
+ }
+ catch (Exception exception)
+ {
+ logger.warn("Could not read process name from resource file {}, reason is '{}'", bpmnFile,
+ exception.getMessage());
+ return Optional.empty();
+ }
+ }
+
+ private List getFields(Reflections reflections)
{
- List fields = new ArrayList<>(reflections.getFieldsAnnotatedWith(annotation));
+ List fields = new ArrayList<>(reflections.getFieldsAnnotatedWith(Documentation.class));
Collections.reverse(fields);
return fields;
}
- private void writeFields(List fields, String filename, String configDirectory)
+ private void writeFields(List fields, List pluginProcessNames, String filename,
+ String workingPackage)
{
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename)))
{
- fields.stream().map(this::createDocumentation).forEach(d -> write(writer, filename, d));
+ fields.stream().map(field -> createDocumentation(field, pluginProcessNames))
+ .forEach(d -> write(writer, filename, d));
}
- catch (IOException e)
+ catch (Exception exception)
{
- logger.warn("Could not generate documentation for directory: {}, reason: {}", configDirectory,
- e.getMessage());
+ logger.warn("Could not generate documentation for package {}, reason is '{}'", workingPackage,
+ exception.getMessage());
}
}
- private String createDocumentation(Field field)
+ private String createDocumentation(Field field, List pluginProcessNames)
{
Documentation documentation = field.getAnnotation(Documentation.class);
Value value = field.getAnnotation(Value.class);
String[] valueSplit = value.value().replaceAll("\\$", "").replace("#", "").replace("{", "").replace("}", "")
.split(":");
+ String property = valueSplit[0];
+
+ String environment = property.replace(".", "_").toUpperCase();
+ if (documentation.filePropertySupported())
+ environment = String.format("%s or %s_FILE", environment, environment);
+
+ boolean required = documentation.required();
+
+ String[] documentationProcessNames = documentation.processNames();
+ String processesNamesAsString = getProcessNamesAsString(documentationProcessNames, pluginProcessNames);
+
+ String description = documentation.description();
+ String example = documentation.example();
+ String recommendation = documentation.recommendation();
+
+ String defaultValue = (valueSplit.length == 2 && !"null".equals(valueSplit[1])) ? valueSplit[1]
+ : "not set by default";
+
+ return String.format("### %s\n- **Property:** %s\n- **Required:** %s\n- **Processes:** %s\n"
+ + "- **Description:** %s\n- **Example:** %s\n- **Recommendation:** %s\n" + "- **Default:** %s\n\n",
+ environment, property, required, processesNamesAsString, description, example, recommendation,
+ defaultValue);
+ }
+
+ private String getProcessNamesAsString(String[] documentationProcessNames, List pluginProcessNames)
+ {
+ if (pluginProcessNames.size() == 0)
+ return "Could not read process names from ProcessPluginDefinition";
+
+ if (documentationProcessNames.length == 0)
+ return String.join(", ", pluginProcessNames);
+
+ for (String documentationProcessName : documentationProcessNames)
+ {
+ if (!pluginProcessNames.contains(documentationProcessName))
+ logger.warn(
+ "Documentation contains process with name '{}' which"
+ + " is not part of the processes {} defined in the ProcessPluginDefinition",
+ documentationProcessName, pluginProcessNames);
+ }
- return String.format(
- "### %s\n- **Property:** %s\n- **Required:** %s\n- **Processes:** %s\n- **Description:** %s\n- **Example:** %s\n- **Recommendation:** %s\n- **Default:** %s\n\n",
- documentation.environmentVariables(), valueSplit[0], documentation.required(),
- documentation.processNames(), documentation.description(), documentation.example(),
- documentation.recommendation(),
- (valueSplit.length == 2 && !"null".equals(valueSplit[1])) ? valueSplit[1] : "not set by default");
+ return String.join(", ", documentationProcessNames);
}
private void write(BufferedWriter writer, String filename, String string)
@@ -93,7 +189,7 @@ private void write(BufferedWriter writer, String filename, String string)
}
catch (IOException e)
{
- logger.warn("Writing the following string to file {} failed: \n {} reason: {}", filename, string,
+ logger.warn("Writing the following string to file {} failed: \n {} reason is '{}'", filename, string,
e.getMessage());
}
}
diff --git a/mii-dsf-processes-documentation-generator/src/main/resources/log4j2.xml b/mii-dsf-processes-documentation-generator/src/main/resources/log4j2.xml
index 67a1731..e8e6da7 100644
--- a/mii-dsf-processes-documentation-generator/src/main/resources/log4j2.xml
+++ b/mii-dsf-processes-documentation-generator/src/main/resources/log4j2.xml
@@ -8,9 +8,9 @@
-
-
+
+
diff --git a/mii-dsf-processes-test-data-generator/pom.xml b/mii-dsf-processes-test-data-generator/pom.xml
index 9fb926c..3724159 100644
--- a/mii-dsf-processes-test-data-generator/pom.xml
+++ b/mii-dsf-processes-test-data-generator/pom.xml
@@ -8,7 +8,7 @@
de.medizininformatik-initiative
mii-dsf-processes
- 0.1.0-SNAPSHOT
+ 0.1.0-RC1
diff --git a/mii-dsf-processes-test-data-generator/src/main/resources/log4j2.xml b/mii-dsf-processes-test-data-generator/src/main/resources/log4j2.xml
index 67a1731..e8e6da7 100644
--- a/mii-dsf-processes-test-data-generator/src/main/resources/log4j2.xml
+++ b/mii-dsf-processes-test-data-generator/src/main/resources/log4j2.xml
@@ -8,9 +8,9 @@
-
-
+
+
diff --git a/pom.xml b/pom.xml
index 544a723..fba3abd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
de.medizininformatik-initiative
mii-dsf-processes
- 0.1.0-SNAPSHOT
+ 0.1.0-RC1
pom
@@ -23,6 +23,7 @@
${project.basedir}
5.1.0
0.5.4
+ 2.3.0
mii-dsf-processes
@@ -104,12 +105,6 @@
${hapi.version}
-
- org.reflections
- reflections
- 0.10.2
-
-
de.hs-heilbronn.mi
@@ -129,6 +124,17 @@
1.8.0-beta4
+
+
+ org.apache.tika
+ tika-core
+ ${apache.tika.version}
+
+
+ org.reflections
+ reflections
+ 0.10.2
+
com.fasterxml.jackson.core
jackson-annotations
@@ -185,8 +191,13 @@
-
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.3.0
+
org.apache.maven.plugins
maven-dependency-plugin
diff --git a/src/assembly/zip.xml b/src/assembly/zip.xml
new file mode 100644
index 0000000..d5ad227
--- /dev/null
+++ b/src/assembly/zip.xml
@@ -0,0 +1,26 @@
+
+
+ zip
+
+ zip
+
+
+
+
+ ${project.build.directory}
+
+
+ *.jar
+
+
+
+ ${project.build.directory}/lib
+
+
+ *.jar
+
+
+
+
\ No newline at end of file