diff --git a/.gitignore b/.gitignore
index dc6110c..dec15ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
###
-# mii processes projectathon common ignores
+# mii processes common ignores
###
**/.classpath
**/.project
@@ -9,6 +9,8 @@
**/*.iml
+**/dependency-reduced-pom.xml
+
###
# test data generator ignores
###
diff --git a/mii-dsf-process-kds-report/pom.xml b/mii-dsf-process-kds-report/pom.xml
new file mode 100644
index 0000000..491e436
--- /dev/null
+++ b/mii-dsf-process-kds-report/pom.xml
@@ -0,0 +1,298 @@
+
+
+ 4.0.0
+
+ mii-dsf-process-kds-report
+
+
+ mii-dsf-processes
+ de.medizininformatik-initiative
+ 0.2.0-SNAPSHOT
+
+
+
+ ${project.basedir}/..
+
+
+
+
+ org.highmed.dsf
+ dsf-bpe-process-base
+ provided
+
+
+ de.medizininformatik-initiative
+ mii-dsf-processes-kds-client
+
+
+ org.springframework
+ spring-web
+ provided
+
+
+
+ org.highmed.dsf
+ dsf-tools-documentation-generator
+ provided
+
+
+ de.hs-heilbronn.mi
+ log4j2-utils
+ provided
+
+
+
+ org.highmed.dsf
+ dsf-fhir-validation
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.highmed.dsf
+ dsf-bpe-process-base
+ test
+ test-jar
+
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+
+ exec
+
+ prepare-package
+
+
+
+ java
+
+ -classpath
+
+
+ org.highmed.dsf.tools.generator.DocumentationGenerator
+
+
+ de.medizininformatik_initiative.process.kds.report
+
+
+ true
+ true
+ compile
+ ${project.basedir}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+ package
+
+ shade
+
+
+
+
+ de.medizininformatik-initiative:mii-dsf-processes-kds-client
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-process-plugin-to-docker-test-setup/dic1
+ package
+
+ copy
+
+
+
+
+ ${project.groupId}
+ ${project.artifactId}
+ ${project.version}
+
+
+
+ ../mii-dsf-processes-docker-test-setup/dic1/bpe/process
+
+
+
+
+ copy-dependencies/dic1
+ package
+
+ copy
+
+
+
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-client
+ ${hapi.version}
+
+
+
+ ../mii-dsf-processes-docker-test-setup/dic1/bpe/plugin
+
+
+
+
+ copy-process-plugin-to-docker-test-setup/dic2
+ package
+
+ copy
+
+
+
+
+ ${project.groupId}
+ ${project.artifactId}
+ ${project.version}
+
+
+
+ ../mii-dsf-processes-docker-test-setup/dic2/bpe/process
+
+
+
+
+ copy-dependencies/dic2
+ package
+
+ copy
+
+
+
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-client
+ ${hapi.version}
+
+
+
+ ../mii-dsf-processes-docker-test-setup/dic2/bpe/plugin
+
+
+
+
+ copy-process-plugin-to-docker-test-setup/hrp
+ package
+
+ copy
+
+
+
+
+ ${project.groupId}
+ ${project.artifactId}
+ ${project.version}
+
+
+
+ ../mii-dsf-processes-docker-test-setup/hrp/bpe/process
+
+
+
+
+ copy-dependencies/hrp
+ package
+
+ copy
+
+
+
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-client
+ ${hapi.version}
+
+
+
+ ../mii-dsf-processes-docker-test-setup/hrp/bpe/plugin
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+
+
+
+
+ ../mii-dsf-processes-docker-test-setup/dic1/bpe/process
+
+
+ ${project.artifactId}-${project.version}.jar
+
+ false
+
+
+
+ ../mii-dsf-processes-docker-test-setup/dic1/bpe/plugin
+
+
+ hapi-fhir-client-${hapi.version}.jar
+
+ false
+
+
+
+ ../mii-dsf-processes-docker-test-setup/dic2/bpe/process
+
+
+ ${project.artifactId}-${project.version}.jar
+
+ false
+
+
+
+ ../mii-dsf-processes-docker-test-setup/dic2/bpe/plugin
+
+
+ hapi-fhir-client-${hapi.version}.jar
+
+ false
+
+
+
+ ../mii-dsf-processes-docker-test-setup/hrp/bpe/process
+
+
+ ${project.artifactId}-${project.version}.jar
+
+ false
+
+
+
+ ../mii-dsf-processes-docker-test-setup/hrp/bpe/plugin
+
+
+ hapi-fhir-client-${hapi.version}.jar
+
+ false
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/ConstantsKdsReport.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/ConstantsKdsReport.java
new file mode 100644
index 0000000..77a62bf
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/ConstantsKdsReport.java
@@ -0,0 +1,82 @@
+package de.medizininformatik_initiative.process.kds.report;
+
+import static de.medizininformatik_initiative.process.kds.report.KdsReportProcessPluginDefinition.VERSION;
+
+public interface ConstantsKdsReport
+{
+ String PROCESS_NAME_KDS_REPORT_AUTOSTART = "kdsReportAutostart";
+ String PROCESS_NAME_KDS_REPORT_RECEIVE = "kdsReportReceive";
+ String PROCESS_NAME_KDS_REPORT_SEND = "kdsReportSend";
+
+ String PROCESS_NAME_FULL_KDS_REPORT_AUTOSTART = "medizininformatik-initiativede_"
+ + PROCESS_NAME_KDS_REPORT_AUTOSTART;
+ String PROCESS_NAME_FULL_KDS_REPORT_RECEIVE = "medizininformatik-initiativede_" + PROCESS_NAME_KDS_REPORT_RECEIVE;
+ String PROCESS_NAME_FULL_KDS_REPORT_SEND = "medizininformatik-initiativede_" + PROCESS_NAME_KDS_REPORT_SEND;
+
+ String BPMN_EXECUTION_VARIABLE_KDS_REPORT_TIMER_INTERVAL = "kdsReportTimerInterval";
+ String BPMN_EXECUTION_VARIABLE_KDS_REPORT_STOP_TIMER = "kdsReportStopTimer";
+ String BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE = "kdsReportSearchBundle";
+ String BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE_RESPONSE_REFERENCE = "kdsReportSearchBundleResponseReference";
+ String BPMN_EXECUTION_VARIABLE_KDS_REPORT_RECEIVE_ERROR = "kdsReportReceiveError";
+
+ String KDS_REPORT_TIMER_INTERVAL_DEFAULT_VALUE = "P7D";
+ String FHIR_STORE_TYPE_BLAZE = "blaze";
+
+ String PROFILE_KDS_REPORT_SEARCH_BUNDLE = "http://medizininformatik-initiative.de/fhir/Bundle/mii-kds-report-search-bundle"
+ + "|" + VERSION;
+ String PROFILE_KDS_REPORT_SEARCH_BUNDLE_RESPONSE = "http://medizininformatik-initiative.de/fhir/Bundle/mii-kds-report-search-bundle-response"
+ + "|" + VERSION;
+ String EXTENSION_KDS_REPORT_STATUS_ERROR_URL = "http://medizininformatik-initiative.de/fhir/StructureDefinition/extension-mii-kds-report-status-error";
+
+ String CODESYSTEM_MII_KDS_REPORT = "http://medizininformatik-initiative.de/fhir/CodeSystem/kds-report";
+ String CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE = "search-bundle";
+ String CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE_REFERENCE = "search-bundle-reference";
+ String CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE_RESPONSE_REFERENCE = "search-bundle-response-reference";
+ String CODESYSTEM_MII_KDS_REPORT_VALUE_REPORT_STATUS = "kds-report-status";
+ String CODESYSTEM_MII_KDS_REPORT_VALUE_TIMER_INTERVAL = "timer-interval";
+
+ String CODESYSTEM_MII_KDS_REPORT_STATUS = "http://medizininformatik-initiative.de/fhir/CodeSystem/kds-report-status";
+ String CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_ALLOWED = "not-allowed";
+ String CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_REACHABLE = "not-reachable";
+ String CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_MISSING = "receipt-missing";
+ String CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_OK = "receipt-ok";
+ String CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_ERROR = "receipt-error";
+ String CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIVE_OK = "receive-ok";
+ String CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIVE_ERROR = "receive-error";
+
+ String PROCESS_MII_URI_BASE = "http://medizininformatik-initiative.de/bpe/Process/";
+
+ String PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START = "http://medizininformatik-initiative.de/fhir/StructureDefinition/mii-kds-report-task-autostart-start";
+ String PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_AND_LATEST_VERSION = PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START
+ + "|" + VERSION;
+ String PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_PROCESS_URI = PROCESS_MII_URI_BASE
+ + PROCESS_NAME_KDS_REPORT_AUTOSTART + "/";
+ String PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_PROCESS_URI_AND_LATEST_VERSION = PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_PROCESS_URI
+ + VERSION;
+ String PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_MESSAGE_NAME = "kdsReportAutostartStart";
+
+ String PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_STOP = "http://medizininformatik-initiative.de/fhir/StructureDefinition/mii-kds-report-task-autostart-stop";
+ String PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_STOP_AND_LATEST_VERSION = PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_STOP
+ + "|" + VERSION;
+ String PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_STOP_MESSAGE_NAME = "kdsReportAutostartStop";
+
+ String PROFILE_MII_KDS_REPORT_TASK_SEND_START = "http://medizininformatik-initiative.de/fhir/StructureDefinition/mii-kds-report-task-send-start";
+ String PROFILE_MII_KDS_REPORT_TASK_SEND_START_AND_LATEST_VERSION = PROFILE_MII_KDS_REPORT_TASK_SEND_START + "|"
+ + VERSION;
+ String PROFILE_MII_KDS_REPORT_TASK_SEND_START_PROCESS_URI = PROCESS_MII_URI_BASE + PROCESS_NAME_KDS_REPORT_SEND
+ + "/";
+ String PROFILE_KDS_MII_REPORT_TASK_SEND_START_PROCESS_URI_AND_LATEST_VERSION = PROFILE_MII_KDS_REPORT_TASK_SEND_START_PROCESS_URI
+ + VERSION;
+ String PROFILE_MII_KDS_REPORT_TASK_SEND_START_MESSAGE_NAME = "kdsReportSendStart";
+
+ String PROFILE_MII_KDS_REPORT_TASK_SEND = "http://medizininformatik-initiative.de/fhir/StructureDefinition/mii-kds-report-task-send";
+ String PROFILE_MII_KDS_REPORT_TASK_SEND_AND_LATEST_VERSION = PROFILE_MII_KDS_REPORT_TASK_SEND + "|" + VERSION;
+ String PROFILE_MII_KDS_REPORT_TASK_SEND_PROCESS_URI = PROCESS_MII_URI_BASE + PROCESS_NAME_KDS_REPORT_RECEIVE + "/";
+ String PROFILE_MII_KDS_REPORT_TASK_SEND_PROCESS_URI_AND_LATEST_VERSION = PROFILE_MII_KDS_REPORT_TASK_SEND_PROCESS_URI
+ + VERSION;
+ String PROFILE_MII_KDS_REPORT_TASK_SEND_MESSAGE_NAME = "kdsReportSend";
+
+ String PROFILE_MII_KDS_REPORT_TASK_RECEIVE = "http://medizininformatik-initiative.de/fhir/StructureDefinition/mii-kds-report-task-receive";
+ String PROFILE_MII_KDS_REPORT_TASK_RECEIVE_AND_LATEST_VERSION = PROFILE_MII_KDS_REPORT_TASK_RECEIVE + "|" + VERSION;
+ String PROFILE_MII_KDS_REPORT_TASK_RECEIVE_MESSAGE_NAME = "kdsReportReceive";
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/KdsReportProcessPluginDefinition.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/KdsReportProcessPluginDefinition.java
new file mode 100644
index 0000000..6256233
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/KdsReportProcessPluginDefinition.java
@@ -0,0 +1,110 @@
+package de.medizininformatik_initiative.process.kds.report;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.highmed.dsf.bpe.ProcessPluginDefinition;
+import org.highmed.dsf.fhir.resources.AbstractResource;
+import org.highmed.dsf.fhir.resources.ActivityDefinitionResource;
+import org.highmed.dsf.fhir.resources.CodeSystemResource;
+import org.highmed.dsf.fhir.resources.ResourceProvider;
+import org.highmed.dsf.fhir.resources.StructureDefinitionResource;
+import org.highmed.dsf.fhir.resources.ValueSetResource;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.env.PropertyResolver;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.kds.report.spring.config.KdsReportConfig;
+import de.medizininformatik_initiative.processes.kds.client.KdsClientFactory;
+
+public class KdsReportProcessPluginDefinition implements ProcessPluginDefinition
+{
+ public static final String VERSION = "0.2.0";
+ public static final LocalDate RELEASE_DATE = LocalDate.of(2022, 4, 14);
+
+ @Override
+ public String getName()
+ {
+ return "mii-process-kds-report";
+ }
+
+ @Override
+ public String getVersion()
+ {
+ return VERSION;
+ }
+
+ @Override
+ public LocalDate getReleaseDate()
+ {
+ return RELEASE_DATE;
+ }
+
+ @Override
+ public Stream getBpmnFiles()
+ {
+ return Stream.of("bpe/kds-report-autostart.bpmn", "bpe/kds-report-send.bpmn", "bpe/kds-report-receive.bpmn");
+ }
+
+ @Override
+ public Stream> getSpringConfigClasses()
+ {
+ return Stream.of(KdsReportConfig.class);
+ }
+
+ @Override
+ public ResourceProvider getResourceProvider(FhirContext fhirContext, ClassLoader classLoader,
+ PropertyResolver resolver)
+ {
+ var aAutostart = ActivityDefinitionResource.file("fhir/ActivityDefinition/mii-kds-report-autostart.xml");
+ var aReceive = ActivityDefinitionResource.file("fhir/ActivityDefinition/mii-kds-report-receive.xml");
+ var aSend = ActivityDefinitionResource.file("fhir/ActivityDefinition/mii-kds-report-send.xml");
+
+ var cReport = CodeSystemResource.file("fhir/CodeSystem/mii-kds-report.xml");
+ var cReportStatus = CodeSystemResource.file("fhir/CodeSystem/mii-kds-report-status.xml");
+
+ var eReportStatusError = StructureDefinitionResource
+ .file("fhir/StructureDefinition/extension-mii-kds-report-status-error.xml");
+
+ var sAutostartStart = StructureDefinitionResource
+ .file("fhir/StructureDefinition/mii-kds-report-task-autostart-start.xml");
+ var sAutostartStop = StructureDefinitionResource
+ .file("fhir/StructureDefinition/mii-kds-report-task-autostart-stop.xml");
+ var sSearchBundle = StructureDefinitionResource
+ .file("fhir/StructureDefinition/mii-kds-report-search-bundle.xml");
+ var sSearchBundleResponse = StructureDefinitionResource
+ .file("fhir/StructureDefinition/mii-kds-report-search-bundle-response.xml");
+ var sReceive = StructureDefinitionResource.file("fhir/StructureDefinition/mii-kds-report-task-receive.xml");
+ var sSend = StructureDefinitionResource.file("fhir/StructureDefinition/mii-kds-report-task-send.xml");
+ var sSendStart = StructureDefinitionResource
+ .file("fhir/StructureDefinition/mii-kds-report-task-send-start.xml");
+
+ var vReport = ValueSetResource.file("fhir/ValueSet/mii-kds-report.xml");
+ var vReportStatusReceive = ValueSetResource.file("fhir/ValueSet/mii-kds-report-status-receive.xml");
+ var vReportStatusSend = ValueSetResource.file("fhir/ValueSet/mii-kds-report-status-send.xml");
+
+ Map> resourcesByProcessKeyAndVersion = Map.of(
+ ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_AUTOSTART + "/" + VERSION,
+ Arrays.asList(aAutostart, cReport, sAutostartStart, sAutostartStop, vReport),
+ ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_RECEIVE + "/" + VERSION,
+ Arrays.asList(aReceive, cReport, cReportStatus, eReportStatusError, sSend, sSearchBundle,
+ sSearchBundleResponse, vReport, vReportStatusReceive),
+ ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_SEND + "/" + VERSION,
+ Arrays.asList(aSend, cReport, cReportStatus, eReportStatusError, sReceive, sSearchBundle,
+ sSearchBundleResponse, sSendStart, vReport, vReportStatusSend));
+
+ return ResourceProvider.read(VERSION, RELEASE_DATE,
+ () -> fhirContext.newXmlParser().setStripVersionsFromReferences(false), classLoader, resolver,
+ resourcesByProcessKeyAndVersion);
+ }
+
+ @Override
+ public void onProcessesDeployed(ApplicationContext pluginApplicationContext, List activeProcesses)
+ {
+ if (activeProcesses.contains(ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_SEND))
+ pluginApplicationContext.getBean(KdsClientFactory.class).testConnection();
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/message/SendKdsReport.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/message/SendKdsReport.java
new file mode 100644
index 0000000..b06748d
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/message/SendKdsReport.java
@@ -0,0 +1,101 @@
+package de.medizininformatik_initiative.process.kds.report.message;
+
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE_RESPONSE_REFERENCE;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_ALLOWED;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_REACHABLE;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE_RESPONSE_REFERENCE;
+
+import java.util.Objects;
+import java.util.stream.Stream;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+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.AbstractTaskMessageSend;
+import org.highmed.dsf.fhir.task.TaskHelper;
+import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.ResourceType;
+import org.hl7.fhir.r4.model.Task;
+import org.springframework.beans.factory.InitializingBean;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.kds.report.util.KdsReportStatusGenerator;
+
+public class SendKdsReport extends AbstractTaskMessageSend implements InitializingBean
+{
+ private final KdsReportStatusGenerator statusGenerator;
+
+ public SendKdsReport(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, FhirContext fhirContext,
+ KdsReportStatusGenerator statusGenerator)
+ {
+ super(clientProvider, taskHelper, readAccessHelper, organizationProvider, fhirContext);
+
+ this.statusGenerator = statusGenerator;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+ Objects.requireNonNull(statusGenerator, "statusGenerator");
+ }
+
+ @Override
+ protected Stream getAdditionalInputParameters(DelegateExecution execution)
+ {
+ String bundleId = (String) execution
+ .getVariable(BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE_RESPONSE_REFERENCE);
+
+ Task.ParameterComponent parameterComponent = new Task.ParameterComponent();
+ parameterComponent.getType().addCoding().setSystem(CODESYSTEM_MII_KDS_REPORT)
+ .setCode(CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE_RESPONSE_REFERENCE);
+ parameterComponent.setValue(new Reference(bundleId).setType(ResourceType.Bundle.name()));
+
+ return Stream.of(parameterComponent);
+ }
+
+ @Override
+ protected void handleIntermediateThrowEventError(Exception exception, String errorMessage)
+ {
+ Task task = getLeadingTaskFromExecutionVariables();
+
+ if (task != null)
+ {
+ String statusCode = CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_REACHABLE;
+ if (exception instanceof WebApplicationException)
+ {
+ WebApplicationException webApplicationException = (WebApplicationException) exception;
+ if (webApplicationException.getResponse() != null && webApplicationException.getResponse()
+ .getStatus() == Response.Status.FORBIDDEN.getStatusCode())
+ {
+ statusCode = CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_ALLOWED;
+ }
+ }
+
+ task.addOutput(statusGenerator.createKdsReportStatusOutput(statusCode, createErrorMessage(exception)));
+ updateLeadingTaskInExecutionVariables(task);
+ }
+
+ super.handleIntermediateThrowEventError(exception, errorMessage);
+ }
+
+ @Override
+ protected void addErrorMessage(Task task, String errorMessage)
+ {
+ // nothing to do here
+ }
+
+ private String createErrorMessage(Exception exception)
+ {
+ return exception.getClass().getSimpleName()
+ + ((exception.getMessage() != null && !exception.getMessage().isBlank())
+ ? (": " + exception.getMessage())
+ : "");
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/message/SendReceipt.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/message/SendReceipt.java
new file mode 100644
index 0000000..390b4bc
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/message/SendReceipt.java
@@ -0,0 +1,87 @@
+package de.medizininformatik_initiative.process.kds.report.message;
+
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_RECEIVE_ERROR;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_ERROR;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_OK;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIVE_ERROR;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_REPORT_STATUS;
+
+import java.util.Objects;
+import java.util.stream.Stream;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+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.AbstractTaskMessageSend;
+import org.highmed.dsf.fhir.task.TaskHelper;
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.Task;
+import org.hl7.fhir.r4.model.Type;
+import org.springframework.beans.factory.InitializingBean;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.kds.report.util.KdsReportStatusGenerator;
+
+public class SendReceipt extends AbstractTaskMessageSend implements InitializingBean
+{
+ private final KdsReportStatusGenerator kdsReportStatusGenerator;
+
+ public SendReceipt(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, FhirContext fhirContext,
+ KdsReportStatusGenerator kdsReportStatusGenerator)
+ {
+ super(clientProvider, taskHelper, readAccessHelper, organizationProvider, fhirContext);
+ this.kdsReportStatusGenerator = kdsReportStatusGenerator;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+ Objects.requireNonNull(kdsReportStatusGenerator, "kdsReportStatusGenerator");
+ }
+
+ @Override
+ protected Stream getAdditionalInputParameters(DelegateExecution execution)
+ {
+ if (execution.getVariable(BPMN_EXECUTION_VARIABLE_KDS_REPORT_RECEIVE_ERROR) != null)
+ return createReceiptError();
+ else
+ return createReceiptOk();
+ }
+
+ private Stream createReceiptError()
+ {
+ return kdsReportStatusGenerator.transformOutputToInputComponent(getLeadingTaskFromExecutionVariables())
+ .map(this::receiveToReceiptStatus);
+ }
+
+ private Task.ParameterComponent receiveToReceiptStatus(Task.ParameterComponent parameterComponent)
+ {
+ Type value = parameterComponent.getValue();
+ if (value instanceof Coding)
+ {
+ Coding coding = (Coding) value;
+ if (CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIVE_ERROR.equals(coding.getCode()))
+ {
+ coding.setCode(CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_ERROR);
+ }
+ }
+
+ return parameterComponent;
+ }
+
+ private Stream createReceiptOk()
+ {
+ Task.ParameterComponent parameterComponent = new Task.ParameterComponent();
+ parameterComponent.getType().addCoding().setSystem(CODESYSTEM_MII_KDS_REPORT)
+ .setCode(CODESYSTEM_MII_KDS_REPORT_VALUE_REPORT_STATUS);
+ parameterComponent.setValue(new Coding().setSystem(CODESYSTEM_MII_KDS_REPORT_STATUS)
+ .setCode(CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_OK));
+
+ return Stream.of(parameterComponent);
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/message/StartSendKdsReport.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/message/StartSendKdsReport.java
new file mode 100644
index 0000000..675edf7
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/message/StartSendKdsReport.java
@@ -0,0 +1,33 @@
+package de.medizininformatik_initiative.process.kds.report.message;
+
+import java.util.stream.Stream;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+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.AbstractTaskMessageSend;
+import org.highmed.dsf.fhir.task.TaskHelper;
+import org.hl7.fhir.r4.model.Task;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+
+public class StartSendKdsReport extends AbstractTaskMessageSend
+{
+ public StartSendKdsReport(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, FhirContext fhirContext)
+ {
+ super(clientProvider, taskHelper, readAccessHelper, organizationProvider, fhirContext);
+ }
+
+ @Override
+ protected Stream getAdditionalInputParameters(DelegateExecution execution)
+ {
+ return getLeadingTaskFromExecutionVariables().getInput().stream().filter(Task.ParameterComponent::hasType)
+ .filter(i -> i.getType().getCoding().stream()
+ .anyMatch(c -> ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT.equals(c.getSystem())
+ && ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE_REFERENCE
+ .equals(c.getCode())));
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/CheckSearchBundle.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/CheckSearchBundle.java
new file mode 100644
index 0000000..6042d16
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/CheckSearchBundle.java
@@ -0,0 +1,127 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.PROFILE_KDS_REPORT_SEARCH_BUNDLE;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+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.task.TaskHelper;
+import org.hl7.fhir.r4.model.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.util.UriComponents;
+import org.springframework.web.util.UriComponentsBuilder;
+
+public class CheckSearchBundle extends AbstractServiceDelegate
+{
+ private static final Logger logger = LoggerFactory.getLogger(CheckSearchBundle.class);
+
+ private static final Pattern MODIFIERS = Pattern.compile(":.*");
+
+ private static final String CAPABILITY_STATEMENT_PATH = "metadata";
+ private static final String SUMMARY_SEARCH_PARAM = "_summary";
+ private static final String SUMMARY_SEARCH_PARAM_VALUE_COUNT = "count";
+ private static final List VALID_SEARCH_PARAMS = List.of("_profile", "type", SUMMARY_SEARCH_PARAM);
+
+ public CheckSearchBundle(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution)
+ {
+ Bundle bundle = (Bundle) execution.getVariable(BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE);
+
+ testProfile(bundle);
+
+ List searches = bundle.getEntry();
+
+ testNoResources(searches);
+ testRequestMethod(searches);
+ testRequestUrls(searches);
+
+ logger.info("Search Bundle contains only valid requests of type GET and valid search params {}",
+ VALID_SEARCH_PARAMS);
+ }
+
+ private void testProfile(Bundle bundle)
+ {
+ if (bundle.getMeta().getProfile().stream()
+ .noneMatch(p -> PROFILE_KDS_REPORT_SEARCH_BUNDLE.equals(p.getValue())))
+ throw new RuntimeException(
+ "Search Bundle profile does not match expected profile '" + PROFILE_KDS_REPORT_SEARCH_BUNDLE + "'");
+ }
+
+ private void testNoResources(List searches)
+ {
+ if (searches.stream().map(Bundle.BundleEntryComponent::getResource).anyMatch(Objects::nonNull))
+ throw new RuntimeException("Search Bundle contains resources");
+ }
+
+ private void testRequestMethod(List searches)
+ {
+ long httpGetCount = searches.stream().filter(Bundle.BundleEntryComponent::hasRequest)
+ .map(Bundle.BundleEntryComponent::getRequest).filter(Bundle.BundleEntryRequestComponent::hasMethod)
+ .map(Bundle.BundleEntryRequestComponent::getMethod).filter(Bundle.HTTPVerb.GET::equals).count();
+
+ int searchesCount = searches.size();
+
+ if (searchesCount != httpGetCount)
+ throw new RuntimeException("Search Bundle contains HTTP method other then GET");
+ }
+
+ private void testRequestUrls(List searches)
+ {
+ List requests = searches.stream()
+ .filter(Bundle.BundleEntryComponent::hasRequest).map(Bundle.BundleEntryComponent::getRequest)
+ .filter(Bundle.BundleEntryRequestComponent::hasUrl).collect(Collectors.toList());
+
+ int requestCount = requests.size();
+ int searchesCount = searches.size();
+
+ if (searchesCount != requestCount)
+ throw new RuntimeException("Search Bundle contains request without url");
+
+ List uriComponents = requests.stream()
+ .map(r -> UriComponentsBuilder.fromUriString(r.getUrl()).build()).collect(Collectors.toList());
+
+ testContainsSummaryCount(uriComponents);
+ testContainsValidSearchParams(uriComponents);
+ }
+
+ private void testContainsSummaryCount(List uriComponents)
+ {
+ uriComponents.stream().filter(u -> !CAPABILITY_STATEMENT_PATH.equals(u.getPath()))
+ .map(u -> u.getQueryParams().toSingleValueMap()).forEach(this::testSummaryCount);
+ }
+
+ private void testSummaryCount(Map queryParams)
+ {
+ if (!SUMMARY_SEARCH_PARAM_VALUE_COUNT.equals(queryParams.get(SUMMARY_SEARCH_PARAM)))
+ throw new RuntimeException("Search Bundle contains request url without _summary=count");
+ }
+
+ private void testContainsValidSearchParams(List uriComponents)
+ {
+ uriComponents.stream().filter(u -> !CAPABILITY_STATEMENT_PATH.equals(u.getPath()))
+ .map(u -> u.getQueryParams().toSingleValueMap()).forEach(this::testSearchParams);
+ }
+
+ private void testSearchParams(Map queryParams)
+ {
+ if (queryParams.keySet().stream().map(s -> MODIFIERS.matcher(s).replaceAll(""))
+ .anyMatch(s -> !VALID_SEARCH_PARAMS.contains(s)))
+ throw new RuntimeException("Search Bundle contains invalid search params, only allowed search params are "
+ + VALID_SEARCH_PARAMS);
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/CreateKdsReport.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/CreateKdsReport.java
new file mode 100644
index 0000000..87c479e
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/CreateKdsReport.java
@@ -0,0 +1,220 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE_RESPONSE_REFERENCE;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.FHIR_STORE_TYPE_BLAZE;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.PROFILE_KDS_REPORT_SEARCH_BUNDLE_RESPONSE;
+import static org.highmed.dsf.bpe.ConstantsBase.BPMN_EXECUTION_VARIABLE_TARGET;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.camunda.bpm.engine.variable.Variables;
+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.Target;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.CapabilityStatement;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.ResourceType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+import de.medizininformatik_initiative.processes.kds.client.KdsClientFactory;
+import de.medizininformatik_initiative.processes.kds.client.logging.DataLogger;
+
+public class CreateKdsReport extends AbstractServiceDelegate implements InitializingBean
+{
+ private static final Logger logger = LoggerFactory.getLogger(CreateKdsReport.class);
+
+ private static final String CAPABILITY_STATEMENT_PATH = "metadata";
+
+ private final OrganizationProvider organizationProvider;
+ private final KdsClientFactory kdsClientFactory;
+ private final DataLogger dataLogger;
+
+ private final String fhirStoreType;
+
+ public CreateKdsReport(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider,
+ KdsClientFactory kdsClientFactory, String fhirStoreType, DataLogger dataLogger)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+
+ this.organizationProvider = organizationProvider;
+ this.kdsClientFactory = kdsClientFactory;
+ this.fhirStoreType = fhirStoreType;
+ this.dataLogger = dataLogger;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(organizationProvider, "organizationProvider");
+ Objects.requireNonNull(kdsClientFactory, "kdsClientFactory");
+ Objects.requireNonNull(fhirStoreType, "fhirStoreType");
+ Objects.requireNonNull(dataLogger, "dataLogger");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution)
+ {
+ Bundle searchBundle = (Bundle) execution.getVariable(BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE);
+ Target target = (Target) execution.getVariable(BPMN_EXECUTION_VARIABLE_TARGET);
+
+ Bundle responseBundle = executeSearchBundle(searchBundle);
+ Bundle reportBundle = transformToReportBundle(searchBundle, responseBundle, target);
+
+ dataLogger.logResource("Report Bundle: {}", reportBundle);
+
+ String reportReference = storeResponseBundle(reportBundle);
+
+ execution.setVariable(BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE_RESPONSE_REFERENCE,
+ Variables.stringValue(reportReference));
+ }
+
+ private Bundle executeSearchBundle(Bundle searchBundle)
+ {
+ return kdsClientFactory.getKdsClient().executeBatchBundle(searchBundle);
+ }
+
+ private Bundle transformToReportBundle(Bundle searchBundle, Bundle responseBundle, Target target)
+ {
+ Bundle report = new Bundle();
+ report.setMeta(responseBundle.getMeta());
+ report.getMeta().addProfile(PROFILE_KDS_REPORT_SEARCH_BUNDLE_RESPONSE);
+ report.setType(responseBundle.getType());
+ report.getIdentifier().setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER)
+ .setValue(organizationProvider.getLocalIdentifierValue());
+
+ getReadAccessHelper().addLocal(report);
+ getReadAccessHelper().addOrganization(report, target.getOrganizationIdentifierValue());
+
+ for (int i = 0; i < searchBundle.getEntry().size(); i++)
+ {
+ Bundle.BundleEntryComponent responseEntry = responseBundle.getEntry().get(i);
+ Bundle.BundleEntryComponent reportEntry = new Bundle.BundleEntryComponent();
+
+ if (responseEntry.getResource() instanceof Bundle || !responseEntry.hasResource())
+ {
+ toEntryComponentBundleResource(responseEntry, reportEntry,
+ searchBundle.getEntry().get(i).getRequest().getUrl());
+ }
+
+ if (responseEntry.getResource() instanceof CapabilityStatement)
+ {
+ toEntryComponentCapabilityStatementResource(responseEntry, reportEntry);
+ }
+
+ reportEntry.setResponse(responseEntry.getResponse());
+ report.addEntry(reportEntry);
+ }
+
+ // Workaround because Blaze cannot execute a search for metadata in a batch bundle:
+ // https://github.com/samply/blaze/issues/778
+ // TODO: remove if Blaze is fixed
+ fixBlazeCapabilityStatement(searchBundle, report);
+
+ return report;
+ }
+
+ private void toEntryComponentBundleResource(Bundle.BundleEntryComponent responseEntry,
+ Bundle.BundleEntryComponent reportEntry, String url)
+ {
+ Bundle reportEntryBundle = new Bundle();
+ reportEntryBundle.getMeta().setLastUpdated(new Date());
+ reportEntryBundle.addLink().setRelation("self").setUrl(url);
+ reportEntryBundle.setType(Bundle.BundleType.SEARCHSET);
+ reportEntryBundle.setTotal(0);
+
+ if (responseEntry.getResource() instanceof Bundle)
+ {
+ Bundle responseEntryBundle = (Bundle) responseEntry.getResource();
+ reportEntryBundle.setTotal(responseEntryBundle.getTotal());
+ reportEntryBundle.getMeta().setLastUpdated(responseEntryBundle.getMeta().getLastUpdated());
+ }
+
+ reportEntry.setResource(reportEntryBundle);
+ }
+
+ private void toEntryComponentCapabilityStatementResource(Bundle.BundleEntryComponent responseEntry,
+ Bundle.BundleEntryComponent reportEntry)
+ {
+ CapabilityStatement responseEntryCapabilityStatement = (CapabilityStatement) responseEntry.getResource();
+ CapabilityStatement reportEntryCapabilityStatement = new CapabilityStatement();
+
+ reportEntryCapabilityStatement.setKind(CapabilityStatement.CapabilityStatementKind.CAPABILITY);
+ reportEntryCapabilityStatement.setStatus(responseEntryCapabilityStatement.getStatus());
+ reportEntryCapabilityStatement.setDate(responseEntryCapabilityStatement.getDate());
+ reportEntryCapabilityStatement.setName("Server");
+
+ reportEntryCapabilityStatement.getSoftware().setName(responseEntryCapabilityStatement.getSoftware().getName());
+ reportEntryCapabilityStatement.getSoftware()
+ .setVersion(responseEntryCapabilityStatement.getSoftware().getVersion());
+
+ reportEntryCapabilityStatement.setFhirVersion(responseEntryCapabilityStatement.getFhirVersion());
+
+ reportEntryCapabilityStatement.setFormat(responseEntryCapabilityStatement.getFormat().stream()
+ .filter(f -> "application/fhir+xml".equals(f.getCode()) || "application/fhir+json".equals(f.getCode()))
+ .collect(Collectors.toList()));
+
+ List rest = responseEntryCapabilityStatement.getRest();
+
+ rest.stream().map(r -> r.setDocumentation(null)).map(r -> r.setSecurity(null)).map(r -> r.setCompartment(null))
+ .forEach(r -> r.getInteraction().forEach(in -> in.setDocumentation(null)));
+
+ rest.stream().flatMap(r -> r.getResource().stream()).map(r -> r.setProfile(null))
+ .map(r -> r.setSupportedProfile(null)).map(r -> r.setDocumentation(null))
+ .forEach(r -> r.getInteraction().forEach(in -> in.setDocumentation(null)));
+ rest.stream().flatMap(r -> r.getResource().stream()).flatMap(r -> r.getSearchParam().stream())
+ .forEach(s -> s.setDocumentation(null));
+ rest.stream().flatMap(r -> r.getResource().stream()).flatMap(r -> r.getOperation().stream())
+ .forEach(o -> o.setDocumentation(null));
+
+ reportEntryCapabilityStatement.setRest(rest);
+ reportEntry.setResource(reportEntryCapabilityStatement);
+ }
+
+ private String storeResponseBundle(Bundle responseBundle)
+ {
+ IdType bundleIdType = getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn()
+ .updateConditionaly(responseBundle,
+ Map.of("identifier", Collections.singletonList(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER
+ + "|" + organizationProvider.getLocalIdentifierValue())));
+
+ logger.info("Stored report bundle with id '{}'", bundleIdType.getValue());
+
+ return new IdType(getFhirWebserviceClientProvider().getLocalBaseUrl(), ResourceType.Bundle.name(),
+ bundleIdType.getIdPart(), bundleIdType.getVersionIdPart()).getValue();
+ }
+
+ private void fixBlazeCapabilityStatement(Bundle searchBundle, Bundle report)
+ {
+ boolean searchContainsMetadata = searchBundle.getEntry().stream()
+ .filter(Bundle.BundleEntryComponent::hasRequest).map(Bundle.BundleEntryComponent::getRequest)
+ .anyMatch(r -> CAPABILITY_STATEMENT_PATH.equals(r.getUrl()));
+
+ if (searchContainsMetadata && FHIR_STORE_TYPE_BLAZE.equals(fhirStoreType))
+ {
+ CapabilityStatement metadata = kdsClientFactory.getKdsClient().getGenericFhirClient().capabilities()
+ .ofType(CapabilityStatement.class).execute();
+
+ Bundle.BundleEntryComponent metadataResponse = new Bundle.BundleEntryComponent().setResource(metadata);
+ Bundle.BundleEntryComponent reportEntry = report.addEntry()
+ .setResponse(new Bundle.BundleEntryResponseComponent().setStatus("200"));
+ toEntryComponentCapabilityStatementResource(metadataResponse, reportEntry);
+ }
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/DownloadKdsReport.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/DownloadKdsReport.java
new file mode 100644
index 0000000..13db713
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/DownloadKdsReport.java
@@ -0,0 +1,104 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import static java.util.stream.Collectors.toList;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+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.task.TaskHelper;
+import org.highmed.dsf.fhir.variables.FhirResourceValues;
+import org.highmed.fhir.client.FhirWebserviceClient;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.Task;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+import de.medizininformatik_initiative.process.kds.report.util.KdsReportStatusGenerator;
+
+public class DownloadKdsReport extends AbstractServiceDelegate implements InitializingBean
+{
+ private static final Logger logger = LoggerFactory.getLogger(DownloadKdsReport.class);
+
+ private final KdsReportStatusGenerator kdsReportStatusGenerator;
+
+ public DownloadKdsReport(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, KdsReportStatusGenerator kdsReportStatusGenerator)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+
+ this.kdsReportStatusGenerator = kdsReportStatusGenerator;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(kdsReportStatusGenerator, "kdsReportStatusGenerator");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution)
+ {
+ Task task = getLeadingTaskFromExecutionVariables();
+
+ IdType reportReference = getReportReference(task);
+ logger.info("Downloading report with id '{}'...", reportReference.getValue());
+
+ Bundle reportBundle = downloadReportBundle(reportReference, task);
+ execution.setVariable(ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE,
+ FhirResourceValues.create(reportBundle));
+ }
+
+ private IdType getReportReference(Task task)
+ {
+ List reportReferences = getTaskHelper()
+ .getInputParameterReferenceValues(task, ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT,
+ ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE_RESPONSE_REFERENCE)
+ .filter(Reference::hasReference).map(Reference::getReference).collect(toList());
+
+ if (reportReferences.size() < 1)
+ throw new IllegalArgumentException("No report reference present in task with id='" + task.getId() + "'");
+
+ if (reportReferences.size() > 1)
+ logger.warn("Found {} report references in task with id '{}', using only the first",
+ reportReferences.size(), task.getId());
+
+ return new IdType(reportReferences.get(0));
+ }
+
+ private Bundle downloadReportBundle(IdType reportReference, Task task)
+ {
+ FhirWebserviceClient client = getFhirWebserviceClientProvider()
+ .getWebserviceClient(reportReference.getBaseUrl());
+
+ try
+ {
+ if (reportReference.hasVersionIdPart())
+ return client.read(Bundle.class, reportReference.getIdPart(), reportReference.getVersionIdPart());
+ else
+ return client.read(Bundle.class, reportReference.getIdPart());
+ }
+ catch (Exception exception)
+ {
+ task.setStatus(Task.TaskStatus.FAILED);
+ task.addOutput(kdsReportStatusGenerator.createKdsReportStatusOutput(
+ ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIVE_ERROR, exception.getMessage()));
+ updateLeadingTaskInExecutionVariables(task);
+
+ logger.warn("Downloading report with id '{}' failed: {}", reportReference.getValue(),
+ exception.getMessage());
+ throw new BpmnError(ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_RECEIVE_ERROR,
+ exception.getMessage());
+ }
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/DownloadSearchBundle.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/DownloadSearchBundle.java
new file mode 100644
index 0000000..f580a38
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/DownloadSearchBundle.java
@@ -0,0 +1,115 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_ALLOWED;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_REACHABLE;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE;
+import static org.highmed.dsf.bpe.ConstantsBase.BPMN_EXECUTION_VARIABLE_TARGET;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+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.task.TaskHelper;
+import org.highmed.dsf.fhir.variables.FhirResourceValues;
+import org.highmed.dsf.fhir.variables.Target;
+import org.highmed.fhir.client.FhirWebserviceClient;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.Task;
+import org.springframework.beans.factory.InitializingBean;
+
+import de.medizininformatik_initiative.process.kds.report.util.KdsReportStatusGenerator;
+import de.medizininformatik_initiative.processes.kds.client.logging.DataLogger;
+
+public class DownloadSearchBundle extends AbstractServiceDelegate implements InitializingBean
+{
+ private final KdsReportStatusGenerator statusGenerator;
+ private final DataLogger dataLogger;
+
+ public DownloadSearchBundle(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, KdsReportStatusGenerator statusGenerator, DataLogger dataLogger)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+
+ this.statusGenerator = statusGenerator;
+ this.dataLogger = dataLogger;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(statusGenerator, "statusGenerator");
+ Objects.requireNonNull(dataLogger, "dataLogger");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution)
+ {
+ Target target = (Target) execution.getVariable(BPMN_EXECUTION_VARIABLE_TARGET);
+
+ String searchBundleIdentifier = CODESYSTEM_MII_KDS_REPORT + "|" + CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE;
+ Bundle bundle = searchSearchBundle(target, searchBundleIdentifier);
+ dataLogger.logResource("Search Response", bundle);
+
+ Bundle searchBundle = extractSearchBundle(bundle, searchBundleIdentifier);
+ dataLogger.logResource("Search Bundle", searchBundle);
+
+ execution.setVariable(BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE,
+ FhirResourceValues.create(searchBundle));
+ }
+
+ private Bundle searchSearchBundle(Target target, String searchBundleIdentifier)
+ {
+ FhirWebserviceClient client = getFhirWebserviceClientProvider().getWebserviceClient(target.getEndpointUrl());
+
+ try
+ {
+ return client.searchWithStrictHandling(Bundle.class,
+ Map.of("identifier", Collections.singletonList(searchBundleIdentifier)));
+ }
+ catch (WebApplicationException exception)
+ {
+ String statusCode = CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_REACHABLE;
+
+ if (exception.getResponse() != null
+ && exception.getResponse().getStatus() == Response.Status.FORBIDDEN.getStatusCode())
+ {
+ statusCode = CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_ALLOWED;
+ }
+
+ Task task = getLeadingTaskFromExecutionVariables();
+ task.addOutput(statusGenerator.createKdsReportStatusOutput(statusCode, createErrorMessage(exception)));
+ updateLeadingTaskInExecutionVariables(task);
+
+ throw new RuntimeException("Error while reading search Bundle with identifier '" + searchBundleIdentifier
+ + "' from organization '" + task.getRequester().getReference() + "': " + exception.getMessage());
+ }
+ }
+
+ private String createErrorMessage(Exception exception)
+ {
+ return exception.getClass().getSimpleName()
+ + ((exception.getMessage() != null && !exception.getMessage().isBlank())
+ ? (": " + exception.getMessage())
+ : "");
+ }
+
+ private Bundle extractSearchBundle(Bundle bundle, String searchBundleIdentifier)
+ {
+ if (bundle.getTotal() != 1 && !(bundle.getEntryFirstRep().getResource() instanceof Bundle))
+ throw new IllegalStateException("Expected a single search Bundle with identifier '" + searchBundleIdentifier
+ + "' but found " + bundle.getTotal());
+
+ return (Bundle) bundle.getEntryFirstRep().getResource();
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/InsertKdsReport.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/InsertKdsReport.java
new file mode 100644
index 0000000..ec5e5b7
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/InsertKdsReport.java
@@ -0,0 +1,93 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+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.task.TaskHelper;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Identifier;
+import org.hl7.fhir.r4.model.Task;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+import de.medizininformatik_initiative.process.kds.report.util.KdsReportStatusGenerator;
+
+public class InsertKdsReport extends AbstractServiceDelegate implements InitializingBean
+{
+ private static final Logger logger = LoggerFactory.getLogger(InsertKdsReport.class);
+
+ private final KdsReportStatusGenerator kdsReportStatusGenerator;
+
+ public InsertKdsReport(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, KdsReportStatusGenerator kdsReportStatusGenerator)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+
+ this.kdsReportStatusGenerator = kdsReportStatusGenerator;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(kdsReportStatusGenerator, "kdsReportStatusGenerator");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution)
+ {
+ Task task = getLeadingTaskFromExecutionVariables();
+ Identifier reportIdentifier = getReportIdentifier(task);
+
+ Bundle report = (Bundle) execution
+ .getVariable(ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE);
+ report.setId("").getMeta().setVersionId("").setTag(null);
+ report.setIdentifier(reportIdentifier);
+
+ getReadAccessHelper().addLocal(report);
+ getReadAccessHelper().addOrganization(report, task.getRequester().getIdentifier().getValue());
+
+ try
+ {
+ IdType reportId = getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn()
+ .updateConditionaly(report, Map.of("identifier", Collections
+ .singletonList(reportIdentifier.getSystem() + "|" + reportIdentifier.getValue())));
+
+ task.addOutput(kdsReportStatusGenerator
+ .createKdsReportStatusOutput(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIVE_OK));
+ updateLeadingTaskInExecutionVariables(task);
+
+ logger.info("Stored report bundle with id '{}' from organization '{}'", reportId.getValue(),
+ task.getRequester().getIdentifier().getValue());
+ }
+ catch (Exception exception)
+ {
+ task.setStatus(Task.TaskStatus.FAILED);
+ task.addOutput(kdsReportStatusGenerator.createKdsReportStatusOutput(
+ ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIVE_ERROR, exception.getMessage()));
+ updateLeadingTaskInExecutionVariables(task);
+
+ logger.warn("Storing report from Task with id '{}' failed: {}", task.getId(), exception.getMessage());
+ throw new BpmnError(ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_RECEIVE_ERROR,
+ exception.getMessage());
+ }
+ }
+
+ private Identifier getReportIdentifier(Task task)
+ {
+ return new Identifier().setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER)
+ .setValue(task.getRequester().getIdentifier().getValue());
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/SelectTargetDic.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/SelectTargetDic.java
new file mode 100644
index 0000000..efae523
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/SelectTargetDic.java
@@ -0,0 +1,75 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import static org.highmed.dsf.bpe.ConstantsBase.BPMN_EXECUTION_VARIABLE_TARGET;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ENDPOINT_IDENTIFIER;
+
+import java.util.Objects;
+
+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.task.TaskHelper;
+import org.highmed.dsf.fhir.variables.Target;
+import org.highmed.dsf.fhir.variables.TargetValues;
+import org.hl7.fhir.r4.model.Endpoint;
+import org.hl7.fhir.r4.model.Identifier;
+import org.hl7.fhir.r4.model.Task;
+import org.springframework.beans.factory.InitializingBean;
+
+public class SelectTargetDic extends AbstractServiceDelegate implements InitializingBean
+{
+ private final EndpointProvider endpointProvider;
+
+ public SelectTargetDic(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, EndpointProvider endpointProvider)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+
+ this.endpointProvider = endpointProvider;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(endpointProvider, "endpointProvider");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution)
+ {
+ Task task = getLeadingTaskFromExecutionVariables();
+ String dicIdentifier = getDicOrganizationIdentifier(task);
+ Endpoint dicEndpoint = getDicEndpoint(dicIdentifier);
+ Target dicTarget = createTarget(dicIdentifier, dicEndpoint);
+
+ execution.setVariable(BPMN_EXECUTION_VARIABLE_TARGET, TargetValues.create(dicTarget));
+ }
+
+ private String getDicOrganizationIdentifier(Task task)
+ {
+ return task.getRequester().getIdentifier().getValue();
+ }
+
+ private Endpoint getDicEndpoint(String dicIndentifier)
+ {
+ return endpointProvider.getFirstDefaultEndpoint(dicIndentifier).orElseThrow(
+ () -> new RuntimeException("Could not find default endpoint of organization '" + dicIndentifier + "'"));
+ }
+
+ private Target createTarget(String dicIndentifier, Endpoint dicEndpoint)
+ {
+ String dicEndpointIdentifier = getEndpointIdentifierValue(dicEndpoint);
+ return Target.createUniDirectionalTarget(dicIndentifier, dicEndpointIdentifier, dicEndpoint.getAddress());
+ }
+
+ private String getEndpointIdentifierValue(Endpoint endpoint)
+ {
+ return endpoint.getIdentifier().stream()
+ .filter(i -> NAMINGSYSTEM_HIGHMED_ENDPOINT_IDENTIFIER.equals(i.getSystem())).findFirst()
+ .map(Identifier::getValue).get();
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/SelectTargetHrp.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/SelectTargetHrp.java
new file mode 100644
index 0000000..c24bf5f
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/SelectTargetHrp.java
@@ -0,0 +1,109 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import static org.highmed.dsf.bpe.ConstantsBase.BPMN_EXECUTION_VARIABLE_TARGET;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_ORGANIZATION_ROLE_VALUE_HRP;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ENDPOINT_IDENTIFIER;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER_MEDICAL_INFORMATICS_INITIATIVE_CONSORTIUM;
+
+import java.util.Objects;
+
+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.highmed.dsf.fhir.variables.Target;
+import org.highmed.dsf.fhir.variables.TargetValues;
+import org.hl7.fhir.r4.model.Endpoint;
+import org.hl7.fhir.r4.model.Identifier;
+import org.hl7.fhir.r4.model.Organization;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+public class SelectTargetHrp extends AbstractServiceDelegate implements InitializingBean
+{
+ private static final Logger logger = LoggerFactory.getLogger(SelectTargetHrp.class);
+
+ private final OrganizationProvider organizationProvider;
+ private final EndpointProvider endpointProvider;
+
+ public SelectTargetHrp(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider,
+ EndpointProvider endpointProvider)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+
+ this.organizationProvider = organizationProvider;
+ this.endpointProvider = endpointProvider;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(organizationProvider, "organizationProvider");
+ Objects.requireNonNull(endpointProvider, "endpointProvider");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution)
+ {
+ Organization organization = getHrpOrganization();
+ String organizationIdentifier = extractHrpIdentifier(organization);
+
+ Endpoint endpoint = getHrpEndpoint(organizationIdentifier);
+ String endpointIdentifier = extractEndpointIdentifier(endpoint);
+
+ Target target = createHrpTarget(organizationIdentifier, endpointIdentifier, endpoint.getAddress());
+
+ logger.info("Using HRP with identifier '{}' and endpoint '{}'", target.getOrganizationIdentifierValue(),
+ target.getEndpointUrl());
+
+ execution.setVariable(BPMN_EXECUTION_VARIABLE_TARGET, TargetValues.create(target));
+ }
+
+ private Organization getHrpOrganization()
+ {
+ return organizationProvider
+ .getOrganizationsByConsortiumAndRole(
+ NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER_MEDICAL_INFORMATICS_INITIATIVE_CONSORTIUM,
+ CODESYSTEM_HIGHMED_ORGANIZATION_ROLE_VALUE_HRP)
+ .findFirst()
+ .orElseThrow(() -> new RuntimeException("Could not find any organization with role HRP in consortium '"
+ + NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER_MEDICAL_INFORMATICS_INITIATIVE_CONSORTIUM
+ + "'"));
+ }
+
+ private Endpoint getHrpEndpoint(String identifier)
+ {
+ return endpointProvider.getFirstDefaultEndpoint(identifier).orElseThrow(
+ () -> new RuntimeException("Could not find any endpoint of HRP with identifier '" + identifier + "'"));
+ }
+
+ private String extractHrpIdentifier(Organization organization)
+ {
+ return organization.getIdentifier().stream()
+ .filter(i -> NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER.equals(i.getSystem()))
+ .map(Identifier::getValue).findFirst()
+ .orElseThrow(() -> new RuntimeException("organization is missing identifier of type '"
+ + NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER + "'"));
+ }
+
+ private String extractEndpointIdentifier(Endpoint endpoint)
+ {
+ return endpoint.getIdentifier().stream()
+ .filter(i -> NAMINGSYSTEM_HIGHMED_ENDPOINT_IDENTIFIER.equals(i.getSystem())).map(Identifier::getValue)
+ .findFirst().orElseThrow(() -> new RuntimeException(
+ "Endpoint is missing identifier of type '" + NAMINGSYSTEM_HIGHMED_ENDPOINT_IDENTIFIER + "'"));
+ }
+
+ private Target createHrpTarget(String organizationIdentifier, String endpointIdentifier, String endpointAddress)
+ {
+ return Target.createUniDirectionalTarget(organizationIdentifier, endpointIdentifier, endpointAddress);
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/StartTimer.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/StartTimer.java
new file mode 100644
index 0000000..001b955
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/StartTimer.java
@@ -0,0 +1,103 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import static org.highmed.dsf.bpe.ConstantsBase.BPMN_EXECUTION_VARIABLE_TARGET;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.camunda.bpm.engine.RuntimeService;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.camunda.bpm.engine.runtime.ProcessInstance;
+import org.camunda.bpm.engine.variable.Variables;
+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.highmed.dsf.fhir.variables.Target;
+import org.highmed.dsf.fhir.variables.TargetValues;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+
+public class StartTimer extends AbstractServiceDelegate implements InitializingBean
+{
+ private static final Logger logger = LoggerFactory.getLogger(StartTimer.class);
+
+ private final OrganizationProvider organizationProvider;
+ private final EndpointProvider endpointProvider;
+
+ public StartTimer(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider,
+ EndpointProvider endpointProvider)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+
+ this.organizationProvider = organizationProvider;
+ this.endpointProvider = endpointProvider;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(organizationProvider, "organizationProvider");
+ Objects.requireNonNull(endpointProvider, "endpointProvider");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution) throws Exception
+ {
+ logger.info("Stopping active instances of process with id '{}'",
+ ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_AUTOSTART);
+ stopActiveInstancesOfProcess();
+
+ logger.debug("Setting variable '{}' to false",
+ ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_STOP_TIMER);
+ execution.setVariable(ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_STOP_TIMER,
+ Variables.booleanValue(false));
+
+ String timerInterval = getTimerInterval();
+ logger.debug("Setting variable '{}' to {}",
+ ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_TIMER_INTERVAL, timerInterval);
+ execution.setVariable(ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_TIMER_INTERVAL,
+ Variables.stringValue(timerInterval));
+
+ execution.setVariable(BPMN_EXECUTION_VARIABLE_TARGET,
+ TargetValues.create(Target.createUniDirectionalTarget(organizationProvider.getLocalIdentifierValue(),
+ endpointProvider.getLocalEndpointIdentifier().getValue(),
+ endpointProvider.getLocalEndpointAddress())));
+ }
+
+ private void stopActiveInstancesOfProcess()
+ {
+ RuntimeService runtimeService = execution.getProcessEngineServices().getRuntimeService();
+
+ String currentInstanceId = execution.getActivityInstanceId();
+ List activeInstances = runtimeService.createProcessInstanceQuery()
+ .processDefinitionKey(ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_AUTOSTART).active().list();
+
+ logger.debug("Found {} active instance{} of process with id '{}'{}", activeInstances.size(),
+ activeInstances.size() == 1 ? "" : "s", ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_AUTOSTART,
+ activeInstances.size() == 0 ? ", nothing to delete"
+ : activeInstances.size() == 1 ? ", deleting it" : ", deleting all of them");
+
+ activeInstances.stream().filter(i -> !currentInstanceId.equals(i.getProcessInstanceId()))
+ .forEach(i -> runtimeService.deleteProcessInstance(i.getProcessInstanceId(),
+ "Only one process instance with id '"
+ + ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_AUTOSTART + "' can exist"));
+ }
+
+ private String getTimerInterval()
+ {
+ return getTaskHelper()
+ .getFirstInputParameterStringValue(getLeadingTaskFromExecutionVariables(),
+ ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT,
+ ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_TIMER_INTERVAL)
+ .orElse(ConstantsKdsReport.KDS_REPORT_TIMER_INTERVAL_DEFAULT_VALUE);
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/StopTimer.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/StopTimer.java
new file mode 100644
index 0000000..65ae4a2
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/StopTimer.java
@@ -0,0 +1,31 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.camunda.bpm.engine.variable.Variables;
+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.task.TaskHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+
+public class StopTimer extends AbstractServiceDelegate
+{
+ private static final Logger logger = LoggerFactory.getLogger(StopTimer.class);
+
+ public StopTimer(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution) throws Exception
+ {
+ logger.debug("Setting variable '{}' to true", ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_STOP_TIMER);
+ execution.setVariable(ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_STOP_TIMER,
+ Variables.booleanValue(true));
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/StoreReceipt.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/StoreReceipt.java
new file mode 100644
index 0000000..a90af91
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/service/StoreReceipt.java
@@ -0,0 +1,113 @@
+package de.medizininformatik_initiative.process.kds.report.service;
+
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY;
+
+import java.util.Objects;
+import java.util.Optional;
+
+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.task.TaskHelper;
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.Task;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+import de.medizininformatik_initiative.process.kds.report.util.KdsReportStatusGenerator;
+
+public class StoreReceipt extends AbstractServiceDelegate implements InitializingBean
+{
+ private static final Logger logger = LoggerFactory.getLogger(StoreReceipt.class);
+
+ private final KdsReportStatusGenerator statusGenerator;
+
+ public StoreReceipt(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
+ ReadAccessHelper readAccessHelper, KdsReportStatusGenerator statusGenerator)
+ {
+ super(clientProvider, taskHelper, readAccessHelper);
+
+ this.statusGenerator = statusGenerator;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(statusGenerator, "statusGenerator");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution)
+ {
+ Task leadingTask = getLeadingTaskFromExecutionVariables();
+ Task currentTask = getCurrentTaskFromExecutionVariables();
+
+ if (!currentTask.getId().equals(leadingTask.getId()))
+ handleReceivedResponse(leadingTask, currentTask);
+ else
+ handleMissingResponse(leadingTask);
+
+ addBusinessKeyOutput(leadingTask, execution);
+ writeStatusLog(leadingTask);
+ updateLeadingTaskInExecutionVariables(leadingTask);
+ }
+
+ private void handleReceivedResponse(Task leadingTask, Task currentTask)
+ {
+ statusGenerator.transformInputToOutput(currentTask, leadingTask);
+
+ if (leadingTask.getOutput().stream().filter(Task.TaskOutputComponent::hasExtension)
+ .flatMap(o -> o.getExtension().stream())
+ .anyMatch(e -> ConstantsKdsReport.EXTENSION_KDS_REPORT_STATUS_ERROR_URL.equals(e.getUrl())))
+ leadingTask.setStatus(Task.TaskStatus.FAILED);
+
+ // The currentTask finishes here but is not automatically set to completed
+ // because it is an additional currentTask during the execution of the main process
+ currentTask.setStatus(Task.TaskStatus.COMPLETED);
+ getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn().update(currentTask);
+ }
+
+ private void handleMissingResponse(Task leadingTask)
+ {
+ leadingTask.setStatus(Task.TaskStatus.FAILED);
+ leadingTask.addOutput(statusGenerator.createKdsReportStatusOutput(
+ ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_MISSING));
+ }
+
+ private void addBusinessKeyOutput(Task leadingTask, DelegateExecution execution)
+ {
+ Optional businessKey = getTaskHelper().getFirstInputParameterStringValue(leadingTask,
+ CODESYSTEM_HIGHMED_BPMN, CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+
+ if (businessKey.isEmpty())
+ leadingTask.addOutput(getTaskHelper().createOutput(CODESYSTEM_HIGHMED_BPMN,
+ CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY, execution.getBusinessKey()));
+ }
+
+ private void writeStatusLog(Task leadingTask)
+ {
+ leadingTask.getOutput().stream().filter(o -> o.getValue() instanceof Coding).map(o -> (Coding) o.getValue())
+ .filter(c -> ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS.equals(c.getSystem()))
+ .forEach(c -> doWriteStatusLog(c, leadingTask.getId()));
+ }
+
+ private void doWriteStatusLog(Coding status, String taskId)
+ {
+ String code = status.getCode();
+ String extension = status.hasExtension()
+ ? " and extension '" + status.getExtensionFirstRep().getUrl() + "|"
+ + status.getExtensionFirstRep().getValueAsPrimitive().getValueAsString() + "'"
+ : "";
+
+ if (ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_OK.equals(code))
+ logger.info("Task with id '{}' has report-status code '{}'{}", taskId, code, extension);
+ else
+ logger.warn("Task with id '{}' has report-status code '{}'{}", taskId, code, extension);
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/spring/config/KdsReportConfig.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/spring/config/KdsReportConfig.java
new file mode 100644
index 0000000..abbfc38
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/spring/config/KdsReportConfig.java
@@ -0,0 +1,156 @@
+package de.medizininformatik_initiative.process.kds.report.spring.config;
+
+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.highmed.dsf.tools.generator.ProcessDocumentation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.kds.report.message.SendKdsReport;
+import de.medizininformatik_initiative.process.kds.report.message.SendReceipt;
+import de.medizininformatik_initiative.process.kds.report.message.StartSendKdsReport;
+import de.medizininformatik_initiative.process.kds.report.service.CheckSearchBundle;
+import de.medizininformatik_initiative.process.kds.report.service.CreateKdsReport;
+import de.medizininformatik_initiative.process.kds.report.service.DownloadKdsReport;
+import de.medizininformatik_initiative.process.kds.report.service.DownloadSearchBundle;
+import de.medizininformatik_initiative.process.kds.report.service.InsertKdsReport;
+import de.medizininformatik_initiative.process.kds.report.service.SelectTargetDic;
+import de.medizininformatik_initiative.process.kds.report.service.SelectTargetHrp;
+import de.medizininformatik_initiative.process.kds.report.service.StartTimer;
+import de.medizininformatik_initiative.process.kds.report.service.StopTimer;
+import de.medizininformatik_initiative.process.kds.report.service.StoreReceipt;
+import de.medizininformatik_initiative.process.kds.report.util.KdsReportStatusGenerator;
+import de.medizininformatik_initiative.processes.kds.client.spring.config.PropertiesConfig;
+
+@Configuration
+@ComponentScan(basePackages = "de.medizininformatik_initiative")
+public class KdsReportConfig
+{
+ @Autowired
+ private FhirWebserviceClientProvider clientProvider;
+
+ @Autowired
+ private TaskHelper taskHelper;
+
+ @Autowired
+ private ReadAccessHelper readAccessHelper;
+
+ @Autowired
+ private OrganizationProvider organizationProvider;
+
+ @Autowired
+ private EndpointProvider endpointProvider;
+
+ @Autowired
+ private FhirContext fhirContext;
+
+ @Autowired
+ private PropertiesConfig kdsFhirClientConfig;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_kdsReportSend" }, description = "The KDS FHIR server type, possible values are [blaze, other] ; must be set, if a Blaze server is used")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.type:other}")
+ private String fhirStoreType;
+
+ // kdsReportAutostart Process
+
+ @Bean
+ public StartTimer startTimer()
+ {
+ return new StartTimer(clientProvider, taskHelper, readAccessHelper, organizationProvider, endpointProvider);
+ }
+
+ @Bean
+ public StopTimer stopTimer()
+ {
+ return new StopTimer(clientProvider, taskHelper, readAccessHelper);
+ }
+
+ @Bean
+ public StartSendKdsReport startSendKdsReport()
+ {
+ return new StartSendKdsReport(clientProvider, taskHelper, readAccessHelper, organizationProvider, fhirContext);
+ }
+
+ // kdsReportSend Process
+
+ @Bean
+ public SelectTargetHrp selectTargetHrp()
+ {
+ return new SelectTargetHrp(clientProvider, taskHelper, readAccessHelper, organizationProvider,
+ endpointProvider);
+ }
+
+ @Bean
+ public DownloadSearchBundle downloadSearchBundle()
+ {
+ return new DownloadSearchBundle(clientProvider, taskHelper, readAccessHelper, kdsReportStatusGenerator(),
+ kdsFhirClientConfig.dataLogger());
+ }
+
+ @Bean
+ public CheckSearchBundle checkSearchBundle()
+ {
+ return new CheckSearchBundle(clientProvider, taskHelper, readAccessHelper);
+ }
+
+ @Bean
+ public CreateKdsReport createKdsReport()
+ {
+ return new CreateKdsReport(clientProvider, taskHelper, readAccessHelper, organizationProvider,
+ kdsFhirClientConfig.kdsClientFactory(), fhirStoreType, kdsFhirClientConfig.dataLogger());
+ }
+
+ @Bean
+ public KdsReportStatusGenerator kdsReportStatusGenerator()
+ {
+ return new KdsReportStatusGenerator();
+ }
+
+ @Bean
+ public SendKdsReport sendKdsReport()
+ {
+ return new SendKdsReport(clientProvider, taskHelper, readAccessHelper, organizationProvider, fhirContext,
+ kdsReportStatusGenerator());
+ }
+
+ @Bean
+ public StoreReceipt storeReceipt()
+ {
+ return new StoreReceipt(clientProvider, taskHelper, readAccessHelper, kdsReportStatusGenerator());
+ }
+
+ // kdsReportReceive Process
+
+ @Bean
+ public DownloadKdsReport downloadKdsReport()
+ {
+ return new DownloadKdsReport(clientProvider, taskHelper, readAccessHelper, kdsReportStatusGenerator());
+ }
+
+ @Bean
+ public InsertKdsReport insertKdsReport()
+ {
+ return new InsertKdsReport(clientProvider, taskHelper, readAccessHelper, kdsReportStatusGenerator());
+ }
+
+ @Bean
+ public SelectTargetDic selectTargetDic()
+ {
+ return new SelectTargetDic(clientProvider, taskHelper, readAccessHelper, endpointProvider);
+ }
+
+ @Bean
+ public SendReceipt sendReceipt()
+ {
+ return new SendReceipt(clientProvider, taskHelper, readAccessHelper, organizationProvider, fhirContext,
+ kdsReportStatusGenerator());
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/util/KdsReportStatusGenerator.java b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/util/KdsReportStatusGenerator.java
new file mode 100644
index 0000000..da71370
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/java/de/medizininformatik_initiative/process/kds/report/util/KdsReportStatusGenerator.java
@@ -0,0 +1,105 @@
+package de.medizininformatik_initiative.process.kds.report.util;
+
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_REPORT_STATUS;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.EXTENSION_KDS_REPORT_STATUS_ERROR_URL;
+
+import java.util.stream.Stream;
+
+import org.hl7.fhir.r4.model.BackboneElement;
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.Task;
+import org.hl7.fhir.r4.model.Task.ParameterComponent;
+import org.hl7.fhir.r4.model.Task.TaskOutputComponent;
+
+public class KdsReportStatusGenerator
+{
+ public ParameterComponent createKdsReportStatusInput(String statusCode)
+ {
+ return createKdsReportStatusInput(statusCode, null);
+ }
+
+ public ParameterComponent createKdsReportStatusInput(String statusCode, String errorMessage)
+ {
+ ParameterComponent input = new ParameterComponent();
+ input.setValue(new Coding().setSystem(CODESYSTEM_MII_KDS_REPORT_STATUS).setCode(statusCode));
+ input.getType().addCoding().setSystem(CODESYSTEM_MII_KDS_REPORT)
+ .setCode(CODESYSTEM_MII_KDS_REPORT_VALUE_REPORT_STATUS);
+
+ if (errorMessage != null)
+ addErrorExtension(input, errorMessage);
+
+ return input;
+ }
+
+ public TaskOutputComponent createKdsReportStatusOutput(String statusCode)
+ {
+ return createKdsReportStatusOutput(statusCode, null);
+ }
+
+ public TaskOutputComponent createKdsReportStatusOutput(String statusCode, String errorMessage)
+ {
+ TaskOutputComponent output = new TaskOutputComponent();
+ output.setValue(new Coding().setSystem(CODESYSTEM_MII_KDS_REPORT_STATUS).setCode(statusCode));
+ output.getType().addCoding().setSystem(CODESYSTEM_MII_KDS_REPORT)
+ .setCode(CODESYSTEM_MII_KDS_REPORT_VALUE_REPORT_STATUS);
+
+ if (errorMessage != null)
+ addErrorExtension(output, errorMessage);
+
+ return output;
+ }
+
+ private void addErrorExtension(BackboneElement element, String errorMessage)
+ {
+ element.addExtension().setUrl(EXTENSION_KDS_REPORT_STATUS_ERROR_URL).setValue(new StringType(errorMessage));
+ }
+
+ public void transformInputToOutput(Task inputTask, Task outputTask)
+ {
+ transformInputToOutputComponents(inputTask).forEach(outputTask::addOutput);
+ }
+
+ public Stream transformInputToOutputComponents(Task inputTask)
+ {
+ return inputTask.getInput().stream()
+ .filter(i -> i.getType().getCoding().stream()
+ .anyMatch(c -> CODESYSTEM_MII_KDS_REPORT.equals(c.getSystem())
+ && CODESYSTEM_MII_KDS_REPORT_VALUE_REPORT_STATUS.equals(c.getCode())))
+ .map(this::toTaskOutputComponent);
+ }
+
+ private TaskOutputComponent toTaskOutputComponent(ParameterComponent inputComponent)
+ {
+ TaskOutputComponent outputComponent = new TaskOutputComponent().setType(inputComponent.getType())
+ .setValue(inputComponent.getValue().copy());
+ outputComponent.setExtension(inputComponent.getExtension());
+
+ return outputComponent;
+ }
+
+ public void transformOutputToInput(Task outputTask, Task inputTask)
+ {
+ transformOutputToInputComponent(outputTask).forEach(inputTask::addInput);
+ }
+
+ public Stream transformOutputToInputComponent(Task outputTask)
+ {
+ return outputTask.getOutput().stream()
+ .filter(i -> i.getType().getCoding().stream()
+ .anyMatch(c -> CODESYSTEM_MII_KDS_REPORT.equals(c.getSystem())
+ && CODESYSTEM_MII_KDS_REPORT_VALUE_REPORT_STATUS.equals(c.getCode())))
+ .map(this::toTaskInputComponent);
+ }
+
+ private ParameterComponent toTaskInputComponent(TaskOutputComponent outputComponent)
+ {
+ ParameterComponent inputComponent = new ParameterComponent().setType(outputComponent.getType())
+ .setValue(outputComponent.getValue().copy());
+ inputComponent.setExtension(outputComponent.getExtension());
+
+ return inputComponent;
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/main/resources/META-INF/services/org.highmed.dsf.bpe.ProcessPluginDefinition b/mii-dsf-process-kds-report/src/main/resources/META-INF/services/org.highmed.dsf.bpe.ProcessPluginDefinition
new file mode 100644
index 0000000..1dacf91
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/META-INF/services/org.highmed.dsf.bpe.ProcessPluginDefinition
@@ -0,0 +1 @@
+de.medizininformatik_initiative.process.kds.report.KdsReportProcessPluginDefinition
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/bpe/kds-report-autostart.bpmn b/mii-dsf-process-kds-report/src/main/resources/bpe/kds-report-autostart.bpmn
new file mode 100644
index 0000000..2032806
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/bpe/kds-report-autostart.bpmn
@@ -0,0 +1,241 @@
+
+
+
+
+ Flow_0stek1z
+
+
+ Flow_05mfu8d
+ Flow_1ltiore
+ Flow_0g1txh0
+ Flow_0jy9ipp
+
+
+ Flow_09o8bb5
+
+
+
+ Flow_1bbw6lm
+ Flow_05mfu8d
+ Flow_06toths
+
+
+ Flow_1asxc2j
+ Flow_1ltiore
+
+ ${kdsReportTimerInterval}
+
+
+
+ Flow_0y9pdwn
+ Flow_13osd7u
+ Flow_0stek1z
+
+
+
+
+
+
+ ${kdsReportStopTimer}
+
+
+ Flow_1yj8623
+ Flow_1asxc2j
+ Flow_1h835ja
+
+
+ ${!kdsReportStopTimer}
+
+
+ ${kdsReportStopTimer}
+
+
+ Flow_06toths
+ Flow_0y9pdwn
+
+ Flow_1x5v76c
+
+
+ Flow_0m0cias
+ Flow_1vxlaau
+
+
+ Flow_1x5v76c
+ Flow_0m0cias
+
+
+
+
+
+ Flow_1vxlaau
+
+
+
+
+
+
+ ${!kdsReportStopTimer}
+
+
+
+ Flow_09o8bb5
+ Flow_1bbw6lm
+
+
+ Flow_1h835ja
+ Flow_0g1txh0
+ Flow_13osd7u
+
+
+
+
+
+
+ http://medizininformatik-initiative.de/fhir/StructureDefinition/mii-kds-report-task-send-start|#{version}
+ kdsReportSendStart
+ http://medizininformatik-initiative.de/bpe/Process/kdsReportSend/#{version}
+
+
+ Flow_0jy9ipp
+ Flow_1yj8623
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mii-dsf-process-kds-report/src/main/resources/bpe/kds-report-receive.bpmn b/mii-dsf-process-kds-report/src/main/resources/bpe/kds-report-receive.bpmn
new file mode 100644
index 0000000..79cb374
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/bpe/kds-report-receive.bpmn
@@ -0,0 +1,132 @@
+
+
+
+
+ SequenceFlow_07w11cw
+
+
+
+
+
+
+ http://medizininformatik-initiative.de/bpe/Process/kdsReportSend/#{version}
+ kdsReportReceive
+ http://medizininformatik-initiative.de/fhir/StructureDefinition/mii-kds-report-task-receive|#{version}
+
+
+ Flow_01ez25z
+
+
+
+
+ SequenceFlow_07w11cw
+ SequenceFlow_09i9zb8
+
+
+ Flow_0h57p0t
+ Flow_01ez25z
+
+
+
+ SequenceFlow_09i9zb8
+ Flow_0epmqlh
+
+
+ Flow_01x9gay
+
+
+
+ Flow_0lhidy1
+
+
+
+ Flow_01x9gay
+ Flow_0lhidy1
+ Flow_0epmqlh
+ Flow_0h57p0t
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mii-dsf-process-kds-report/src/main/resources/bpe/kds-report-send.bpmn b/mii-dsf-process-kds-report/src/main/resources/bpe/kds-report-send.bpmn
new file mode 100644
index 0000000..c6a7a55
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/bpe/kds-report-send.bpmn
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+ SequenceFlow_0k1j79c
+ SequenceFlow_05ia6lz
+
+
+ Flow_0d1hhpd
+
+
+ SequenceFlow_0k1j79c
+
+
+
+
+ Flow_0lez18n
+ Flow_0d1hhpd
+
+
+
+ Flow_1bwmt5h
+ Flow_0gkokuw
+
+
+
+
+ http://medizininformatik-initiative.de/bpe/Process/kdsReportReceive/#{version}
+ kdsReportSend
+ http://medizininformatik-initiative.de/fhir/StructureDefinition/mii-kds-report-task-send|#{version}
+
+
+ Flow_0gkokuw
+ Flow_0hq9yqb
+
+
+
+
+ Flow_0zp2a01
+ Flow_06wgdy0
+
+
+
+
+
+ Flow_0hq9yqb
+ Flow_0zp2a01
+ Flow_1fi7ktr
+
+
+ Flow_1fi7ktr
+ Flow_085f33c
+
+ PT5M
+
+
+
+
+ Flow_06wgdy0
+ Flow_085f33c
+ Flow_0lez18n
+
+
+
+
+
+ SequenceFlow_05ia6lz
+ Flow_0bq8udu
+
+
+
+ Flow_0bq8udu
+ Flow_1bwmt5h
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/ActivityDefinition/mii-kds-report-autostart.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/ActivityDefinition/mii-kds-report-autostart.xml
new file mode 100644
index 0000000..d1da3e9
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/ActivityDefinition/mii-kds-report-autostart.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/ActivityDefinition/mii-kds-report-receive.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/ActivityDefinition/mii-kds-report-receive.xml
new file mode 100644
index 0000000..a8e0050
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/ActivityDefinition/mii-kds-report-receive.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/ActivityDefinition/mii-kds-report-send.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/ActivityDefinition/mii-kds-report-send.xml
new file mode 100644
index 0000000..373ae8a
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/ActivityDefinition/mii-kds-report-send.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/CodeSystem/mii-kds-report-status.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/CodeSystem/mii-kds-report-status.xml
new file mode 100644
index 0000000..c016d56
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/CodeSystem/mii-kds-report-status.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/CodeSystem/mii-kds-report.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/CodeSystem/mii-kds-report.xml
new file mode 100644
index 0000000..f3add72
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/CodeSystem/mii-kds-report.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/extension-mii-kds-report-status-error.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/extension-mii-kds-report-status-error.xml
new file mode 100644
index 0000000..33ea31d
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/extension-mii-kds-report-status-error.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-search-bundle-response.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-search-bundle-response.xml
new file mode 100644
index 0000000..b3567ee
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-search-bundle-response.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-search-bundle.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-search-bundle.xml
new file mode 100644
index 0000000..ff28721
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-search-bundle.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-autostart-start.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-autostart-start.xml
new file mode 100644
index 0000000..a72f974
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-autostart-start.xml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-autostart-stop.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-autostart-stop.xml
new file mode 100644
index 0000000..1df65a9
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-autostart-stop.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-receive.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-receive.xml
new file mode 100644
index 0000000..8063e3c
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-receive.xml
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-send-start.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-send-start.xml
new file mode 100644
index 0000000..5e7b6d1
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-send-start.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-send.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-send.xml
new file mode 100644
index 0000000..72f0fd2
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/StructureDefinition/mii-kds-report-task-send.xml
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/ValueSet/mii-kds-report-status-receive.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/ValueSet/mii-kds-report-status-receive.xml
new file mode 100644
index 0000000..f0ff3ae
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/ValueSet/mii-kds-report-status-receive.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/ValueSet/mii-kds-report-status-send.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/ValueSet/mii-kds-report-status-send.xml
new file mode 100644
index 0000000..6191da1
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/ValueSet/mii-kds-report-status-send.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/main/resources/fhir/ValueSet/mii-kds-report.xml b/mii-dsf-process-kds-report/src/main/resources/fhir/ValueSet/mii-kds-report.xml
new file mode 100644
index 0000000..3780b23
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/main/resources/fhir/ValueSet/mii-kds-report.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/CheckSearchBundleServiceTest.java b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/CheckSearchBundleServiceTest.java
new file mode 100644
index 0000000..dfe8299
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/CheckSearchBundleServiceTest.java
@@ -0,0 +1,148 @@
+package de.medizininformatik_initiative.process.kds.report.bpe;
+
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_ERROR;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.InputStream;
+import java.util.UUID;
+
+import org.camunda.bpm.engine.ProcessEngine;
+import org.camunda.bpm.engine.RuntimeService;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
+import org.highmed.dsf.fhir.task.TaskHelper;
+import org.highmed.fhir.client.FhirWebserviceClient;
+import org.highmed.fhir.client.PreferReturnMinimalWithRetry;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Task;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+import de.medizininformatik_initiative.process.kds.report.service.CheckSearchBundle;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CheckSearchBundleServiceTest
+{
+ @Mock
+ private DelegateExecution execution;
+
+ @Mock
+ private TaskHelper taskHelper;
+
+ @Mock
+ private FhirWebserviceClientProvider clientProvider;
+
+ @Mock
+ private FhirWebserviceClient webserviceClient;
+
+ @Mock
+ private PreferReturnMinimalWithRetry preferReturnMinimalWithRetry;
+
+ @Mock
+ private ProcessEngine processEngine;
+
+ @Mock
+ private RuntimeService runtimeService;
+
+ @Captor
+ ArgumentCaptor system;
+
+ @Captor
+ ArgumentCaptor code;
+
+ @Captor
+ ArgumentCaptor error;
+
+ @InjectMocks
+ private CheckSearchBundle service;
+
+ @Test
+ public void testValid()
+ {
+ testValid("/fhir/Bundle/search-bundle.xml");
+
+ }
+
+ @Test
+ public void testInvalidResource()
+ {
+ testInvalid("/fhir/Bundle/search-bundle-invalid-resource.xml", "resources");
+ }
+
+ @Test
+ public void testInvalidRequestMethod()
+ {
+ testInvalid("/fhir/Bundle/search-bundle-invalid-request-method.xml", "GET");
+ }
+
+ @Test
+ public void testInvalidNoSummary()
+ {
+ testInvalid("/fhir/Bundle/search-bundle-invalid-no-summary.xml", "_summary=count");
+ }
+
+ @Test
+ public void testInvalidParam()
+ {
+ testInvalid("/fhir/Bundle/search-bundle-invalid-param.xml", "invalid search params");
+ }
+
+ private void testValid(String pathToBundle)
+ {
+ try (InputStream in = getClass().getResourceAsStream(pathToBundle))
+ {
+ Bundle bundle = FhirContext.forR4().newXmlParser().parseResource(Bundle.class, in);
+ Mockito.when(execution.getVariable(ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE))
+ .thenReturn(bundle);
+
+ service.execute(execution);
+ }
+ catch (Exception exception)
+ {
+ fail();
+ }
+ }
+
+ private void testInvalid(String pathToBundle, String errorContains)
+ {
+ Task task = (Task) new Task().setId(UUID.randomUUID().toString());
+
+ try (InputStream in = getClass().getResourceAsStream(pathToBundle))
+ {
+ Bundle bundle = FhirContext.forR4().newXmlParser().parseResource(Bundle.class, in);
+ Mockito.when(execution.getVariable(ConstantsKdsReport.BPMN_EXECUTION_VARIABLE_KDS_REPORT_SEARCH_BUNDLE))
+ .thenReturn(bundle);
+ Mockito.when(execution.getVariable("task")).thenReturn(task);
+ Mockito.when(execution.getProcessDefinitionId()).thenReturn("processDefinitionId");
+ Mockito.when(execution.getActivityInstanceId()).thenReturn("activityInstanceId");
+ Mockito.when(clientProvider.getLocalWebserviceClient()).thenReturn(webserviceClient);
+ Mockito.when(webserviceClient.withMinimalReturn()).thenReturn(preferReturnMinimalWithRetry);
+ Mockito.when(preferReturnMinimalWithRetry.update(task)).thenReturn(new IdType(task.getId()));
+ Mockito.when(execution.getProcessEngine()).thenReturn(processEngine);
+ Mockito.when(processEngine.getRuntimeService()).thenReturn(runtimeService);
+
+ service.execute(execution);
+ Mockito.verify(taskHelper).createOutput(system.capture(), code.capture(), error.capture());
+
+ assertEquals(CODESYSTEM_HIGHMED_BPMN, system.getValue());
+ assertEquals(CODESYSTEM_HIGHMED_BPMN_VALUE_ERROR, code.getValue());
+ assertTrue(error.getValue().contains(errorContains));
+ }
+ catch (Exception exception)
+ {
+ fail();
+ }
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/KdsReportProcessPluginDefinitionTest.java b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/KdsReportProcessPluginDefinitionTest.java
new file mode 100644
index 0000000..3426b13
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/KdsReportProcessPluginDefinitionTest.java
@@ -0,0 +1,43 @@
+package de.medizininformatik_initiative.process.kds.report.bpe;
+
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_AUTOSTART;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_RECEIVE;
+import static de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport.PROCESS_NAME_FULL_KDS_REPORT_SEND;
+import static de.medizininformatik_initiative.process.kds.report.KdsReportProcessPluginDefinition.VERSION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.highmed.dsf.bpe.ProcessPluginDefinition;
+import org.highmed.dsf.fhir.resources.ResourceProvider;
+import org.junit.Test;
+import org.springframework.core.env.StandardEnvironment;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.kds.report.KdsReportProcessPluginDefinition;
+
+public class KdsReportProcessPluginDefinitionTest
+{
+ @Test
+ public void testResourceLoading()
+ {
+ ProcessPluginDefinition definition = new KdsReportProcessPluginDefinition();
+ ResourceProvider provider = definition.getResourceProvider(FhirContext.forR4(), getClass().getClassLoader(),
+ new StandardEnvironment());
+ assertNotNull(provider);
+
+ var kdsReportAutostart = provider.getResources(PROCESS_NAME_FULL_KDS_REPORT_AUTOSTART + "/" + VERSION,
+ s -> ResourceProvider.empty());
+ assertNotNull(kdsReportAutostart);
+ assertEquals(5, kdsReportAutostart.count());
+
+ var kdsReportReceive = provider.getResources(PROCESS_NAME_FULL_KDS_REPORT_RECEIVE + "/" + VERSION,
+ s -> ResourceProvider.empty());
+ assertNotNull(kdsReportReceive);
+ assertEquals(9, kdsReportReceive.count());
+
+ var kdsReportSend = provider.getResources(PROCESS_NAME_FULL_KDS_REPORT_SEND + "/" + VERSION,
+ s -> ResourceProvider.empty());
+ assertNotNull(kdsReportSend);
+ assertEquals(10, kdsReportSend.count());
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/start/KdsReportAutostartStartExampleStarter.java b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/start/KdsReportAutostartStartExampleStarter.java
new file mode 100644
index 0000000..4786fec
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/start/KdsReportAutostartStartExampleStarter.java
@@ -0,0 +1,63 @@
+package de.medizininformatik_initiative.process.kds.report.bpe.start;
+
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.highmed.dsf.bpe.start.ExampleStarter;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.ResourceType;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.Task;
+
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+
+public class KdsReportAutostartStartExampleStarter
+{
+ public static final String AUTOSTART_BUSINESS_KEY = "9ad28295-eccc-41c2-b0f0-c9db0b229f26";
+
+ private static final String DIC_URL = "https://dic1/fhir";
+ private static final String DIC_IDENTIFIER = "Test_DIC1";
+
+ public static void main(String[] args) throws Exception
+ {
+ ExampleStarter starter = ExampleStarter.forServer(args, DIC_URL);
+
+ Task task = createTask();
+ starter.startWith(task);
+ }
+
+ private static Task createTask()
+ {
+ Task task = new Task();
+ task.setIdElement(new IdType("urn:uuid:" + UUID.randomUUID().toString()));
+
+ task.getMeta().addProfile(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START);
+ task.setInstantiatesUri(
+ ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_PROCESS_URI_AND_LATEST_VERSION);
+ task.setStatus(Task.TaskStatus.REQUESTED);
+ task.setIntent(Task.TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue(DIC_IDENTIFIER);
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue(DIC_IDENTIFIER);
+
+ task.addInput().setValue(new StringType(AUTOSTART_BUSINESS_KEY)).getType().addCoding()
+ .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+ task.addInput()
+ .setValue(new StringType(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+
+ task.addInput().setValue(new StringType("PT5M")).getType().addCoding()
+ .setSystem(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT)
+ .setCode(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_TIMER_INTERVAL);
+
+ return task;
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/start/KdsReportAutostartStopExampleStarter.java b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/start/KdsReportAutostartStopExampleStarter.java
new file mode 100644
index 0000000..467caab
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/start/KdsReportAutostartStopExampleStarter.java
@@ -0,0 +1,56 @@
+package de.medizininformatik_initiative.process.kds.report.bpe.start;
+
+import static de.medizininformatik_initiative.process.kds.report.bpe.start.KdsReportAutostartStartExampleStarter.AUTOSTART_BUSINESS_KEY;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.highmed.dsf.bpe.start.ExampleStarter;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.ResourceType;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.Task;
+
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+
+public class KdsReportAutostartStopExampleStarter
+{
+ private static final String DIC_URL = "https://dic1/fhir";
+ private static final String DIC_IDENTIFIER = "Test_DIC1";
+
+ public static void main(String[] args) throws Exception
+ {
+ Task task = createTask();
+ ExampleStarter.forServer(args, DIC_URL).startWith(task);
+ }
+
+ private static Task createTask()
+ {
+ Task task = new Task();
+ task.setIdElement(new IdType("urn:uuid:" + UUID.randomUUID().toString()));
+
+ task.getMeta().addProfile(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_STOP);
+ task.setInstantiatesUri(
+ ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_PROCESS_URI_AND_LATEST_VERSION);
+ task.setStatus(Task.TaskStatus.REQUESTED);
+ task.setIntent(Task.TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue(DIC_IDENTIFIER);
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue(DIC_IDENTIFIER);
+
+ task.addInput()
+ .setValue(new StringType(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_STOP_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+ task.addInput().setValue(new StringType(AUTOSTART_BUSINESS_KEY)).getType().addCoding()
+ .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+
+ return task;
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/start/KdsReportSendExampleStarter.java b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/start/KdsReportSendExampleStarter.java
new file mode 100644
index 0000000..5f5443e
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/bpe/start/KdsReportSendExampleStarter.java
@@ -0,0 +1,53 @@
+package de.medizininformatik_initiative.process.kds.report.bpe.start;
+
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.highmed.dsf.bpe.start.ExampleStarter;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.ResourceType;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.Task;
+
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+
+public class KdsReportSendExampleStarter
+{
+ private static final String DIC_URL = "https://dic1/fhir";
+ private static final String DIC_IDENTIFIER = "Test_DIC1";
+
+ public static void main(String[] args) throws Exception
+ {
+ ExampleStarter starter = ExampleStarter.forServer(args, DIC_URL);
+
+ Task task = createTask();
+ starter.startWith(task);
+ }
+
+ private static Task createTask()
+ {
+ Task task = new Task();
+ task.setIdElement(new IdType("urn:uuid:" + UUID.randomUUID().toString()));
+
+ task.getMeta().addProfile(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_SEND_START);
+ task.setInstantiatesUri(
+ ConstantsKdsReport.PROFILE_KDS_MII_REPORT_TASK_SEND_START_PROCESS_URI_AND_LATEST_VERSION);
+ task.setStatus(Task.TaskStatus.REQUESTED);
+ task.setIntent(Task.TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue(DIC_IDENTIFIER);
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue(DIC_IDENTIFIER);
+
+ task.addInput().setValue(new StringType(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_SEND_START_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+
+ return task;
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/fhir/profile/ActivityDefinitionProfileTest.java b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/fhir/profile/ActivityDefinitionProfileTest.java
new file mode 100644
index 0000000..b15d6ee
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/fhir/profile/ActivityDefinitionProfileTest.java
@@ -0,0 +1,93 @@
+package de.medizininformatik_initiative.process.kds.report.fhir.profile;
+
+import static de.medizininformatik_initiative.process.kds.report.KdsReportProcessPluginDefinition.RELEASE_DATE;
+import static de.medizininformatik_initiative.process.kds.report.KdsReportProcessPluginDefinition.VERSION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+import org.highmed.dsf.fhir.authorization.process.ProcessAuthorizationHelper;
+import org.highmed.dsf.fhir.authorization.process.ProcessAuthorizationHelperImpl;
+import org.highmed.dsf.fhir.validation.ResourceValidator;
+import org.highmed.dsf.fhir.validation.ResourceValidatorImpl;
+import org.highmed.dsf.fhir.validation.ValidationSupportRule;
+import org.hl7.fhir.r4.model.ActivityDefinition;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ca.uhn.fhir.validation.ResultSeverityEnum;
+import ca.uhn.fhir.validation.ValidationResult;
+
+public class ActivityDefinitionProfileTest
+{
+ private static final Logger logger = LoggerFactory.getLogger(ActivityDefinitionProfileTest.class);
+
+ @ClassRule
+ public static final ValidationSupportRule validationRule = new ValidationSupportRule(VERSION, RELEASE_DATE,
+ Arrays.asList("highmed-activity-definition-0.5.0.xml", "highmed-extension-process-authorization-0.5.0.xml",
+ "highmed-extension-process-authorization-consortium-role-0.5.0.xml",
+ "highmed-extension-process-authorization-organization-0.5.0.xml",
+ "highmed-coding-process-authorization-local-all-0.5.0.xml",
+ "highmed-coding-process-authorization-local-consortium-role-0.5.0.xml",
+ "highmed-coding-process-authorization-local-organization-0.5.0.xml",
+ "highmed-coding-process-authorization-remote-all-0.5.0.xml",
+ "highmed-coding-process-authorization-remote-consortium-role-0.5.0.xml",
+ "highmed-coding-process-authorization-remote-organization-0.5.0.xml"),
+ Arrays.asList("highmed-read-access-tag-0.5.0.xml", "highmed-process-authorization-0.5.0.xml"),
+ Arrays.asList("highmed-read-access-tag-0.5.0.xml", "highmed-process-authorization-recipient-0.5.0.xml",
+ "highmed-process-authorization-requester-0.5.0.xml"));
+
+ private final ResourceValidator resourceValidator = new ResourceValidatorImpl(validationRule.getFhirContext(),
+ validationRule.getValidationSupport());
+
+ private final ProcessAuthorizationHelper processAuthorizationHelper = new ProcessAuthorizationHelperImpl();
+
+ @Test
+ public void testAutostartValid() throws Exception
+ {
+ ActivityDefinition ad = validationRule.readActivityDefinition(
+ Paths.get("src/main/resources/fhir/ActivityDefinition/mii-kds-report-autostart.xml"));
+
+ ValidationResult result = resourceValidator.validate(ad);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+
+ assertTrue(processAuthorizationHelper.isValid(ad, taskProfile -> true, orgIdentifier -> true, role -> true));
+ }
+
+ @Test
+ public void testSendValid() throws Exception
+ {
+ ActivityDefinition ad = validationRule.readActivityDefinition(
+ Paths.get("src/main/resources/fhir/ActivityDefinition/mii-kds-report-send.xml"));
+
+ ValidationResult result = resourceValidator.validate(ad);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+
+ assertTrue(processAuthorizationHelper.isValid(ad, taskProfile -> true, orgIdentifier -> true, role -> true));
+ }
+
+ @Test
+ public void testReceiveValid() throws Exception
+ {
+ ActivityDefinition ad = validationRule.readActivityDefinition(
+ Paths.get("src/main/resources/fhir/ActivityDefinition/mii-kds-report-receive.xml"));
+
+ ValidationResult result = resourceValidator.validate(ad);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+
+ assertTrue(processAuthorizationHelper.isValid(ad, taskProfile -> true, orgIdentifier -> true, role -> true));
+ }
+}
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/fhir/profile/TaskProfileTest.java b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/fhir/profile/TaskProfileTest.java
new file mode 100644
index 0000000..2dc3fce
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/java/de/medizininformatik_initiative/process/kds/report/fhir/profile/TaskProfileTest.java
@@ -0,0 +1,352 @@
+package de.medizininformatik_initiative.process.kds.report.fhir.profile;
+
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.UUID;
+
+import org.highmed.dsf.fhir.validation.ResourceValidator;
+import org.highmed.dsf.fhir.validation.ResourceValidatorImpl;
+import org.highmed.dsf.fhir.validation.ValidationSupportRule;
+import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.ResourceType;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.Task;
+import org.hl7.fhir.r4.model.Task.TaskIntent;
+import org.hl7.fhir.r4.model.Task.TaskStatus;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ca.uhn.fhir.validation.ResultSeverityEnum;
+import ca.uhn.fhir.validation.ValidationResult;
+import de.medizininformatik_initiative.process.kds.report.ConstantsKdsReport;
+import de.medizininformatik_initiative.process.kds.report.KdsReportProcessPluginDefinition;
+import de.medizininformatik_initiative.process.kds.report.util.KdsReportStatusGenerator;
+
+public class TaskProfileTest
+{
+ private static final Logger logger = LoggerFactory.getLogger(TaskProfileTest.class);
+
+ @ClassRule
+ public static final ValidationSupportRule validationRule = new ValidationSupportRule(
+ KdsReportProcessPluginDefinition.VERSION, KdsReportProcessPluginDefinition.RELEASE_DATE,
+ Arrays.asList("highmed-task-base-0.5.0.xml", "extension-mii-kds-report-status-error.xml",
+ "mii-kds-report-search-bundle.xml", "mii-kds-report-search-bundle-response.xml",
+ "mii-kds-report-task-autostart-start.xml", "mii-kds-report-task-autostart-stop.xml",
+ "mii-kds-report-task-receive.xml", "mii-kds-report-task-send.xml",
+ "mii-kds-report-task-send-start.xml"),
+ Arrays.asList("highmed-read-access-tag-0.5.0.xml", "highmed-bpmn-message-0.5.0.xml", "mii-kds-report.xml",
+ "mii-kds-report-status.xml"),
+ Arrays.asList("highmed-read-access-tag-0.5.0.xml", "highmed-bpmn-message-0.5.0.xml", "mii-kds-report.xml",
+ "mii-kds-report-status-receive.xml", "mii-kds-report-status-send.xml"));
+
+ private ResourceValidator resourceValidator = new ResourceValidatorImpl(validationRule.getFhirContext(),
+ validationRule.getValidationSupport());
+
+ @Test
+ public void testTaskAutostartStartProcessProfileValid() throws Exception
+ {
+ Task task = createValidTaskAutostartStartProcess();
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskAutostartStartProcessProfileValidTimerInterval() throws Exception
+ {
+ Task task = createValidTaskAutostartStartProcess();
+ task.addInput().setValue(new StringType("P30D")).getType().addCoding()
+ .setSystem(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT)
+ .setCode(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_TIMER_INTERVAL);
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskStartAutostartProcessProfileNotValidTimerInterval() throws Exception
+ {
+ Task task = createValidTaskAutostartStartProcess();
+ task.addInput().setValue(new StringType("P10X")).getType().addCoding()
+ .setSystem(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT)
+ .setCode(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_TIMER_INTERVAL);
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(1, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ private Task createValidTaskAutostartStartProcess()
+ {
+ Task task = new Task();
+ task.getMeta().addProfile(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START);
+ task.setInstantiatesUri(
+ ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_PROCESS_URI_AND_LATEST_VERSION);
+ task.setStatus(TaskStatus.REQUESTED);
+ task.setIntent(TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("DIC");
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("DIC");
+
+ task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding()
+ .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+ task.addInput()
+ .setValue(new StringType(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+
+ return task;
+ }
+
+ @Test
+ public void testTaskAutostartStopProcessProfileValid() throws Exception
+ {
+ Task task = createValidTaskAutostartStopProcess();
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ private Task createValidTaskAutostartStopProcess()
+ {
+ Task task = new Task();
+ task.getMeta().addProfile(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_STOP);
+ task.setInstantiatesUri(
+ ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_START_PROCESS_URI_AND_LATEST_VERSION);
+ task.setStatus(TaskStatus.REQUESTED);
+ task.setIntent(TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("DIC");
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("DIC");
+
+ task.addInput()
+ .setValue(new StringType(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_AUTOSTART_STOP_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+ task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding()
+ .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+
+ return task;
+ }
+
+ @Test
+ public void testTaskSendStartProcessProfileValid() throws Exception
+ {
+ Task task = createValidTaskSendStartProcess();
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskSendStartProcessProfileValidWithBuisnessKeyOutput() throws Exception
+ {
+ Task task = createValidTaskSendStartProcess();
+ task.addOutput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding()
+ .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskSendStartProcessProfileValidWithBusinessKeyAndKdsReportStatusOutput() throws Exception
+ {
+ Task task = createValidTaskSendStartProcess();
+ task.addOutput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding()
+ .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+ task.addOutput(new KdsReportStatusGenerator()
+ .createKdsReportStatusOutput(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_OK));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskSendStartProcessProfileValidWithBusinessKeyAndKdsReportStatusErrorOutput() throws Exception
+ {
+ Task task = createValidTaskSendStartProcess();
+ task.addOutput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding()
+ .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+ task.addOutput(new KdsReportStatusGenerator().createKdsReportStatusOutput(
+ ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_NOT_REACHABLE, "some error message"));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ private Task createValidTaskSendStartProcess()
+ {
+ Task task = new Task();
+ task.getMeta().addProfile(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_SEND_START);
+ task.setInstantiatesUri(
+ ConstantsKdsReport.PROFILE_KDS_MII_REPORT_TASK_SEND_START_PROCESS_URI_AND_LATEST_VERSION);
+ task.setStatus(TaskStatus.REQUESTED);
+ task.setIntent(TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("DIC");
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("DIC");
+
+ task.addInput().setValue(new StringType(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_SEND_START_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+
+ return task;
+ }
+
+ @Test
+ public void testTaskSendProcessProfileValid() throws Exception
+ {
+ Task task = createValidTaskSendProcess();
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskSendProcessProfileValidWithKdsReportStatusOutput() throws Exception
+ {
+ Task task = createValidTaskSendProcess();
+ task.addOutput(new KdsReportStatusGenerator()
+ .createKdsReportStatusOutput(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIVE_OK));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskSendProcessProfileValidWithKdsReportStatusErrorOutput() throws Exception
+ {
+ Task task = createValidTaskSendProcess();
+ task.addOutput(new KdsReportStatusGenerator().createKdsReportStatusOutput(
+ ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIVE_ERROR, "some error message"));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ private Task createValidTaskSendProcess()
+ {
+ Task task = new Task();
+ task.getMeta().addProfile(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_SEND);
+ task.setInstantiatesUri(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_SEND_PROCESS_URI_AND_LATEST_VERSION);
+ task.setStatus(TaskStatus.REQUESTED);
+ task.setIntent(TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("DIC");
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("HRP");
+
+ task.addInput().setValue(new StringType(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_SEND_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+ task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding()
+ .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+
+ task.addInput()
+ .setValue(new Reference("http://foo.bar/fhir/Bundle/" + UUID.randomUUID())
+ .setType(ResourceType.Bundle.name()))
+ .getType().addCoding().setSystem(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT)
+ .setCode(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_VALUE_SEARCH_BUNDLE_RESPONSE_REFERENCE);
+
+ return task;
+ }
+
+ @Test
+ public void testTaskReceiveProcessProfileValidWithResponseInput() throws Exception
+ {
+ Task task = createValidTaskReceiveProcess();
+ task.addInput(new KdsReportStatusGenerator()
+ .createKdsReportStatusInput(ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_OK));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskReceiveProcessProfileValidWithResponseInputError() throws Exception
+ {
+ Task task = createValidTaskReceiveProcess();
+ task.addInput(new KdsReportStatusGenerator().createKdsReportStatusInput(
+ ConstantsKdsReport.CODESYSTEM_MII_KDS_REPORT_STATUS_VALUE_RECEIPT_ERROR, "some error message"));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ private Task createValidTaskReceiveProcess()
+ {
+ Task task = new Task();
+ task.getMeta().addProfile(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_RECEIVE);
+ task.setInstantiatesUri(
+ ConstantsKdsReport.PROFILE_KDS_MII_REPORT_TASK_SEND_START_PROCESS_URI_AND_LATEST_VERSION);
+ task.setStatus(TaskStatus.REQUESTED);
+ task.setIntent(TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("HRP");
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("DIC");
+
+ task.addInput().setValue(new StringType(ConstantsKdsReport.PROFILE_MII_KDS_REPORT_TASK_RECEIVE_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+ task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding()
+ .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
+
+ return task;
+ }
+}
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-no-summary.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-no-summary.xml
new file mode 100644
index 0000000..3aab1ca
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-no-summary.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-param.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-param.xml
new file mode 100644
index 0000000..0916f23
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-param.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-request-method.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-request-method.xml
new file mode 100644
index 0000000..e7fe975
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-request-method.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-resource.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-resource.xml
new file mode 100644
index 0000000..1dff89c
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-invalid-resource.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-response.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-response.xml
new file mode 100644
index 0000000..22b606a
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle-response.xml
@@ -0,0 +1,37540 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle.xml
new file mode 100644
index 0000000..4fedc2a
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Bundle/search-bundle.xml
@@ -0,0 +1,220 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-autostart-start.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-autostart-start.xml
new file mode 100644
index 0000000..1e23dac
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-autostart-start.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-autostart-stop.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-autostart-stop.xml
new file mode 100644
index 0000000..9a633d6
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-autostart-stop.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-send-start-demo.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-send-start-demo.xml
new file mode 100644
index 0000000..25924b8
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-send-start-demo.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-send-start.xml b/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-send-start.xml
new file mode 100644
index 0000000..cd99968
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/fhir/Task/report-send-start.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-kds-report/src/test/resources/log4j2.xml b/mii-dsf-process-kds-report/src/test/resources/log4j2.xml
new file mode 100644
index 0000000..063dbfa
--- /dev/null
+++ b/mii-dsf-process-kds-report/src/test/resources/log4j2.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mii-dsf-process-projectathon-data-transfer/pom.xml b/mii-dsf-process-projectathon-data-transfer/pom.xml
index c97f7f9..429050b 100644
--- a/mii-dsf-process-projectathon-data-transfer/pom.xml
+++ b/mii-dsf-process-projectathon-data-transfer/pom.xml
@@ -3,12 +3,12 @@
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
+ mii-dsf-process-projectathon-data-transfer
de.medizininformatik-initiative
mii-dsf-processes
- 0.1.0
+ 0.2.0-SNAPSHOT
@@ -22,23 +22,23 @@
provided
- ca.uhn.hapi.fhir
- hapi-fhir-client
- provided
+ de.medizininformatik-initiative
+ mii-dsf-processes-kds-client
org.apache.tika
tika-core
- provided
- de.medizininformatik-initiative
- mii-dsf-processes-documentation-generator
+ org.highmed.dsf
+ dsf-tools-documentation-generator
+ provided
de.hs-heilbronn.mi
log4j2-utils
+ provided
@@ -73,10 +73,10 @@
-classpath
- de.medizininformatik_initiative.processes.documentation.generator.DocumentationGenerator
+ org.highmed.dsf.tools.generator.DocumentationGenerator
- de.medizininformatik_initiative.processes.projectathon.data_transfer
+ de.medizininformatik_initiative.process.projectathon.data_transfer
true
@@ -85,12 +85,32 @@
${project.basedir}
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+ package
+
+ shade
+
+
+
+
+ de.medizininformatik-initiative:mii-dsf-processes-kds-client
+ org.apache.tika:tika-core
+
+
+
+
+
+
org.apache.maven.plugins
maven-dependency-plugin
- copy-process-plugin-to-docker-test-setup/dic
+ copy-process-plugin-to-docker-test-setup/dic1
package
copy
@@ -102,19 +122,14 @@
${project.artifactId}
${project.version}
-
- org.apache.tika
- tika-core
- ${apache.tika.version}
-
- ../mii-dsf-processes-docker-test-setup/dic/bpe/process/${project.artifactId}-${project.version}
+ ../mii-dsf-processes-docker-test-setup/dic1/bpe/process
- copy-dependencies/dic
+ copy-dependencies/dic1
package
copy
@@ -127,7 +142,9 @@
${hapi.version}
- ../mii-dsf-processes-docker-test-setup/dic/bpe/plugin
+
+ ../mii-dsf-processes-docker-test-setup/dic1/bpe/plugin
+
@@ -143,14 +160,9 @@
${project.artifactId}
${project.version}
-
- org.apache.tika
- tika-core
- ${apache.tika.version}
-
- ../mii-dsf-processes-docker-test-setup/cos/bpe/process/${project.artifactId}-${project.version}
+ ../mii-dsf-processes-docker-test-setup/cos/bpe/process
@@ -168,24 +180,9 @@
${hapi.version}
- ../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
+
+ ../mii-dsf-processes-docker-test-setup/cos/bpe/plugin
+
@@ -197,16 +194,16 @@
- ../mii-dsf-processes-docker-test-setup/dic/bpe/process/${project.artifactId}-${project.version}
+ ../mii-dsf-processes-docker-test-setup/dic1/bpe/process
- **
+ ${project.artifactId}-${project.version}.jar
false
- ../mii-dsf-processes-docker-test-setup/dic/bpe/plugin
+ ../mii-dsf-processes-docker-test-setup/dic1/bpe/plugin
hapi-fhir-client-${hapi.version}.jar
@@ -215,10 +212,10 @@
- ../mii-dsf-processes-docker-test-setup/cos/bpe/process/${project.artifactId}-${project.version}
+ ../mii-dsf-processes-docker-test-setup/cos/bpe/process
- **
+ ${project.artifactId}-${project.version}.jar
false
@@ -234,27 +231,6 @@
-
- org.apache.maven.plugins
- maven-assembly-plugin
-
-
- tar-gz-assembly
- install
-
- single
-
-
-
-
- false
-
- src/assembly/tar-gz.xml
-
- 0
- 2202
-
-
\ 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/ConstantsDataTransfer.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/ConstantsDataTransfer.java
similarity index 83%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/ConstantsDataTransfer.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/ConstantsDataTransfer.java
index 271b31d..15d445c 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/ConstantsDataTransfer.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/ConstantsDataTransfer.java
@@ -1,9 +1,15 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer;
+package de.medizininformatik_initiative.process.projectathon.data_transfer;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.DataTransferProcessPluginDefinition.VERSION;
+import static de.medizininformatik_initiative.process.projectathon.data_transfer.DataTransferProcessPluginDefinition.VERSION;
public interface ConstantsDataTransfer
{
+ String PROCESS_NAME_DATA_SEND = "dataSend";
+ String PROCESS_NAME_DATA_RECEIVE = "dataReceive";
+
+ String PROCESS_NAME_FULL_DATA_SEND = "medizininformatik-initiativede_" + PROCESS_NAME_DATA_SEND;
+ String PROCESS_NAME_FULL_DATA_RECEIVE = "medizininformatik-initiativede_" + PROCESS_NAME_DATA_RECEIVE;
+
String BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER = "project-identifier";
String BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER = "coordinating-site-identifier";
String BPMN_EXECUTION_VARIABLE_DATA_SET = "data-set";
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/DataTransferProcessPluginDefinition.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/DataTransferProcessPluginDefinition.java
similarity index 64%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/DataTransferProcessPluginDefinition.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/DataTransferProcessPluginDefinition.java
index 03a7fdd..93a5766 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/DataTransferProcessPluginDefinition.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/DataTransferProcessPluginDefinition.java
@@ -1,5 +1,6 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer;
+package de.medizininformatik_initiative.process.projectathon.data_transfer;
+import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -13,14 +14,17 @@
import org.highmed.dsf.fhir.resources.ResourceProvider;
import org.highmed.dsf.fhir.resources.StructureDefinitionResource;
import org.highmed.dsf.fhir.resources.ValueSetResource;
+import org.springframework.context.ApplicationContext;
import org.springframework.core.env.PropertyResolver;
import ca.uhn.fhir.context.FhirContext;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.spring.config.TransferDataConfig;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.spring.config.TransferDataConfig;
+import de.medizininformatik_initiative.processes.kds.client.KdsClientFactory;
public class DataTransferProcessPluginDefinition implements ProcessPluginDefinition
{
- public static final String VERSION = "0.1.0";
+ public static final String VERSION = "0.2.0";
+ public static final LocalDate RELEASE_DATE = LocalDate.of(2022, 4, 14);
@Override
public String getName()
@@ -34,6 +38,12 @@ public String getVersion()
return VERSION;
}
+ @Override
+ public LocalDate getReleaseDate()
+ {
+ return RELEASE_DATE;
+ }
+
@Override
public Stream getBpmnFiles()
{
@@ -50,28 +60,36 @@ public Stream> getSpringConfigClasses()
public ResourceProvider getResourceProvider(FhirContext fhirContext, ClassLoader classLoader,
PropertyResolver propertyResolver)
{
- var aSen = ActivityDefinitionResource.file("fhir/ActivityDefinition/mii-projectathon-data-send.xml");
var aRec = ActivityDefinitionResource.file("fhir/ActivityDefinition/mii-projectathon-data-receive.xml");
+ var aSen = ActivityDefinitionResource.file("fhir/ActivityDefinition/mii-projectathon-data-send.xml");
var cC = CodeSystemResource.file("fhir/CodeSystem/mii-cryptography.xml");
var cD = CodeSystemResource.file("fhir/CodeSystem/mii-data-transfer.xml");
+
var nP = NamingSystemResource.file("fhir/NamingSystem/mii-project-identifier.xml");
- var sTstaDsen = StructureDefinitionResource
- .file("fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml");
var sTstaDrec = StructureDefinitionResource
.file("fhir/StructureDefinition/mii-projectathon-task-start-data-receive.xml");
+ var sTstaDsen = StructureDefinitionResource
+ .file("fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml");
var vC = ValueSetResource.file("fhir/ValueSet/mii-cryptography.xml");
var vD = ValueSetResource.file("fhir/ValueSet/mii-data-transfer.xml");
Map> resourcesByProcessKeyAndVersion = Map.of( //
- "medizininformatik-initiativede_dataSend/" + VERSION,
- Arrays.asList(aSen, cC, cD, nP, sTstaDsen, vC, vD), //
- "medizininformatik-initiativede_dataReceive/" + VERSION,
- Arrays.asList(aRec, cC, cD, nP, sTstaDrec, vC, vD));
+ ConstantsDataTransfer.PROCESS_NAME_FULL_DATA_RECEIVE + "/" + VERSION,
+ Arrays.asList(aRec, cC, cD, nP, sTstaDrec, vC, vD), //
+ ConstantsDataTransfer.PROCESS_NAME_FULL_DATA_SEND + "/" + VERSION,
+ Arrays.asList(aSen, cC, cD, nP, sTstaDsen, vC, vD));
- return ResourceProvider.read(VERSION, () -> fhirContext.newXmlParser().setStripVersionsFromReferences(false),
- classLoader, propertyResolver, resourcesByProcessKeyAndVersion);
+ return ResourceProvider.read(VERSION, RELEASE_DATE,
+ () -> fhirContext.newXmlParser().setStripVersionsFromReferences(false), classLoader, propertyResolver,
+ resourcesByProcessKeyAndVersion);
+ }
+
+ @Override
+ public void onProcessesDeployed(ApplicationContext pluginApplicationContext, List activeProcesses)
+ {
+ pluginApplicationContext.getBean(KdsClientFactory.class).testConnection();
}
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProvider.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/crypto/KeyProvider.java
similarity index 89%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProvider.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/crypto/KeyProvider.java
index e0b2b65..902c193 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProvider.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/crypto/KeyProvider.java
@@ -1,4 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.crypto;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
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/process/projectathon/data_transfer/crypto/KeyProviderImpl.java
similarity index 80%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProviderImpl.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/crypto/KeyProviderImpl.java
index 5a72db2..f54b004 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/process/projectathon/data_transfer/crypto/KeyProviderImpl.java
@@ -1,7 +1,5 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.crypto;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY;
import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
import static org.hl7.fhir.r4.model.Bundle.BundleType.COLLECTION;
import static org.hl7.fhir.r4.model.DocumentReference.ReferredDocumentStatus.FINAL;
@@ -37,7 +35,8 @@
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.processes.kds.client.logging.DataLogger;
import de.rwh.utils.crypto.io.PemIo;
public class KeyProviderImpl implements KeyProvider, InitializingBean
@@ -61,7 +60,7 @@ public class KeyProviderImpl implements KeyProvider, InitializingBean
*/
public static KeyProviderImpl fromFiles(String privateKeyFile, String publicKeyFile,
FhirWebserviceClientProvider clientProvider, OrganizationProvider organizationProvider,
- ReadAccessHelper readAccessHelper)
+ ReadAccessHelper readAccessHelper, DataLogger dataLogger)
{
logger.info("Configuring KeyProvider with private-key from {} and public-key from {}", privateKeyFile,
publicKeyFile);
@@ -101,7 +100,8 @@ public static KeyProviderImpl fromFiles(String privateKeyFile, String publicKeyF
throw new RuntimeException("Error while reading PublicKey from " + publicKeyFile, e);
}
- return new KeyProviderImpl(privateKey, publicKey, clientProvider, organizationProvider, readAccessHelper);
+ return new KeyProviderImpl(privateKey, publicKey, clientProvider, organizationProvider, readAccessHelper,
+ dataLogger);
}
private final PrivateKey privateKey;
@@ -111,9 +111,10 @@ public static KeyProviderImpl fromFiles(String privateKeyFile, String publicKeyF
private final OrganizationProvider organizationProvider;
private final ReadAccessHelper readAccessHelper;
+ private final DataLogger dataLogger;
public KeyProviderImpl(PrivateKey privateKey, PublicKey publicKey, FhirWebserviceClientProvider clientProvider,
- OrganizationProvider organizationProvider, ReadAccessHelper readAccessHelper)
+ OrganizationProvider organizationProvider, ReadAccessHelper readAccessHelper, DataLogger dataLogger)
{
this.privateKey = privateKey;
this.publicKey = publicKey;
@@ -121,6 +122,7 @@ public KeyProviderImpl(PrivateKey privateKey, PublicKey publicKey, FhirWebservic
this.clientProvider = clientProvider;
this.organizationProvider = organizationProvider;
this.readAccessHelper = readAccessHelper;
+ this.dataLogger = dataLogger;
}
@Override
@@ -129,6 +131,7 @@ public void afterPropertiesSet() throws Exception
Objects.requireNonNull(clientProvider, "clientProvider");
Objects.requireNonNull(organizationProvider, "organizationProvider");
Objects.requireNonNull(readAccessHelper, "readAccessHelper");
+ Objects.requireNonNull(dataLogger, "dataLogger");
}
@EventListener({ ContextRefreshedEvent.class })
@@ -139,8 +142,8 @@ public void onContextRefreshedEvent(ContextRefreshedEvent event)
if (publicKey != null)
{
Bundle output = clientProvider.getLocalWebserviceClient().search(Bundle.class,
- Map.of("identifier", Collections.singletonList(
- CODESYSTEM_MII_CRYPTOGRAPHY + "|" + CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY)));
+ Map.of("identifier", Collections.singletonList(ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY
+ + "|" + ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY)));
Bundle bundleOnServer = null;
@@ -154,14 +157,15 @@ else if (output.getTotal() == 0)
logger.info("Creating new PublicKey Bundle on DSF FHIR server...");
Bundle bundleToCreate = createPublicKeyBundle();
bundleOnServer = clientProvider.getLocalWebserviceClient().createConditionaly(bundleToCreate,
- "identifier=" + CODESYSTEM_MII_CRYPTOGRAPHY + "|"
- + CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY);
+ "identifier=" + ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY + "|"
+ + ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY);
}
else
{
- throw new RuntimeException(
- "Exist " + output.getTotal() + " Bundle with identifier=" + CODESYSTEM_MII_CRYPTOGRAPHY
- + "|" + CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY + ", expected only one");
+ throw new RuntimeException("Exist " + output.getTotal() + " Bundle with identifier="
+ + ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY + "|"
+ + ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY
+ + ", expected only one");
}
logger.info("PublicKey Bundle has id='{}'", bundleOnServer.getId());
@@ -169,7 +173,6 @@ else if (output.getTotal() == 0)
}
catch (Exception exception)
{
- logger.warn("Error while creating PublicKey Bundle: {}", exception.getMessage());
throw new RuntimeException("Error while creating PublicKey Bundle: " + exception.getMessage(), exception);
}
}
@@ -183,8 +186,8 @@ private Bundle createPublicKeyBundle()
binary.setId(UUID.randomUUID().toString());
DocumentReference documentReference = new DocumentReference().setStatus(CURRENT).setDocStatus(FINAL);
- documentReference.getMasterIdentifier().setSystem(CODESYSTEM_MII_CRYPTOGRAPHY)
- .setValue(CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY);
+ documentReference.getMasterIdentifier().setSystem(ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY)
+ .setValue(ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY);
documentReference.addAuthor().setType(ResourceType.Organization.name()).getIdentifier()
.setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER)
.setValue(organizationProvider.getLocalIdentifierValue());
@@ -193,15 +196,15 @@ private Bundle createPublicKeyBundle()
.setUrl("urn:uuid:" + binary.getId()).setHash(DigestUtils.sha256(publicKey.getEncoded()));
Bundle bundle = new Bundle().setType(COLLECTION);
- bundle.getIdentifier().setSystem(CODESYSTEM_MII_CRYPTOGRAPHY)
- .setValue(CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY);
+ bundle.getIdentifier().setSystem(ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY)
+ .setValue(ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY);
bundle.setTimestamp(date);
bundle.addEntry().setResource(documentReference).setFullUrl("urn:uuid:" + documentReference.getId());
bundle.addEntry().setResource(binary).setFullUrl("urn:uuid:" + binary.getId());
readAccessHelper.addAll(bundle);
- LoggingHelper.logDebugBundle("Created Bundle", bundle);
+ dataLogger.logResource("Created PublicKey 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/process/projectathon/data_transfer/crypto/RsaAesGcmUtil.java
similarity index 97%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/crypto/RsaAesGcmUtil.java
index b6d0aa0..de7872e 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/process/projectathon/data_transfer/crypto/RsaAesGcmUtil.java
@@ -1,4 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.crypto;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
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/process/projectathon/data_transfer/message/StartReceiveProcess.java
similarity index 61%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/message/StartReceiveProcess.java
index b94a8cf..a096d48 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/process/projectathon/data_transfer/message/StartReceiveProcess.java
@@ -1,8 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.message;
-
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_DATA_SET_REFERENCE;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.message;
import java.util.stream.Stream;
@@ -17,6 +13,7 @@
import org.hl7.fhir.r4.model.Task.ParameterComponent;
import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
public class StartReceiveProcess extends AbstractTaskMessageSend
{
@@ -29,13 +26,14 @@ public StartReceiveProcess(FhirWebserviceClientProvider clientProvider, TaskHelp
@Override
protected Stream getAdditionalInputParameters(DelegateExecution execution)
{
- String binaryId = (String) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE);
+ String binaryId = (String) execution
+ .getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE);
ParameterComponent parameterComponent = new ParameterComponent();
- parameterComponent.getType().addCoding().setSystem(CODESYSTEM_MII_DATA_TRANSFER)
- .setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_DATA_SET_REFERENCE);
+ parameterComponent.getType().addCoding().setSystem(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER)
+ .setCode(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_DATA_SET_REFERENCE);
parameterComponent.setValue(new Reference().setType(ResourceType.Binary.name()).setReference(binaryId));
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/process/projectathon/data_transfer/service/CreateBundle.java
similarity index 68%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/CreateBundle.java
index a19e4ee..1c19be6 100644
--- 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/process/projectathon/data_transfer/service/CreateBundle.java
@@ -1,10 +1,5 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
+package de.medizininformatik_initiative.process.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;
@@ -26,18 +21,21 @@
import org.hl7.fhir.r4.model.ResourceType;
import org.springframework.beans.factory.InitializingBean;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.processes.kds.client.logging.DataLogger;
public class CreateBundle extends AbstractServiceDelegate implements InitializingBean
{
private final OrganizationProvider organizationProvider;
+ private final DataLogger dataLogger;
public CreateBundle(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
- ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider)
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, DataLogger dataLogger)
{
super(clientProvider, taskHelper, readAccessHelper);
this.organizationProvider = organizationProvider;
+ this.dataLogger = dataLogger;
}
@Override
@@ -46,21 +44,24 @@ public void afterPropertiesSet() throws Exception
super.afterPropertiesSet();
Objects.requireNonNull(organizationProvider, "organizationProvider");
+ Objects.requireNonNull(dataLogger, "dataLogger");
}
@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);
+ String projectIdentifier = (String) execution
+ .getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER);
+ DocumentReference documentReference = (DocumentReference) execution
+ .getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE);
+ Binary binary = (Binary) execution.getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BINARY);
Bundle bundle = createTransactionBundle(projectIdentifier, documentReference, binary);
- LoggingHelper.logDebugBundle("Created Bundle", bundle);
+ dataLogger.logResource("Created Transfer Bundle", bundle);
- execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundle));
+ execution.setVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET,
+ FhirResourceValues.create(bundle));
}
private Bundle createTransactionBundle(String projectIdentifier, DocumentReference documentReference, Binary binary)
@@ -70,8 +71,8 @@ private Bundle createTransactionBundle(String projectIdentifier, DocumentReferen
binaryToTransmit.setId(UUID.randomUUID().toString());
DocumentReference documentReferenceToTransmit = new DocumentReference().setStatus(CURRENT).setDocStatus(FINAL);
- documentReferenceToTransmit.getMasterIdentifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER)
- .setValue(projectIdentifier);
+ documentReferenceToTransmit.getMasterIdentifier()
+ .setSystem(ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER).setValue(projectIdentifier);
documentReferenceToTransmit.addAuthor().setType(ResourceType.Organization.name()).getIdentifier()
.setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER)
.setValue(organizationProvider.getLocalIdentifierValue());
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/process/projectathon/data_transfer/service/DecryptData.java
similarity index 74%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/DecryptData.java
index 9efdc7a..37be048 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/process/projectathon/data_transfer/service/DecryptData.java
@@ -1,7 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
-
-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_DATA_SET_ENCRYPTED;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.service;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
@@ -19,22 +16,26 @@
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;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.crypto.KeyProvider;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.crypto.RsaAesGcmUtil;
+import de.medizininformatik_initiative.processes.kds.client.logging.DataLogger;
public class DecryptData extends AbstractServiceDelegate implements InitializingBean
{
private final OrganizationProvider organizationProvider;
private final KeyProvider keyProvider;
+ private final DataLogger dataLogger;
public DecryptData(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
- ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, KeyProvider keyProvider)
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, KeyProvider keyProvider,
+ DataLogger dataLogger)
{
super(clientProvider, taskHelper, readAccessHelper);
this.organizationProvider = organizationProvider;
this.keyProvider = keyProvider;
+ this.dataLogger = dataLogger;
}
@Override
@@ -44,21 +45,24 @@ public void afterPropertiesSet() throws Exception
Objects.requireNonNull(organizationProvider, "organizationProvider");
Objects.requireNonNull(keyProvider, "keyProvider");
+ Objects.requireNonNull(dataLogger, "dataLogger");
}
@Override
protected void doExecute(DelegateExecution execution)
{
- byte[] bundleEncrypted = (byte[]) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED);
+ byte[] bundleEncrypted = (byte[]) execution
+ .getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED);
String localOrganizationIdentifier = organizationProvider.getLocalIdentifierValue();
String sendingOrganizationIdentifier = getSendingOrganizationIdentifier();
Bundle bundleDecrypted = decryptBundle(keyProvider.getPrivateKey(), bundleEncrypted,
sendingOrganizationIdentifier, localOrganizationIdentifier);
- LoggingHelper.logDebugBundle("Decrypted Bundle", bundleDecrypted);
+ dataLogger.logResource("Decrypted Transfer Bundle", bundleDecrypted);
- execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundleDecrypted));
+ execution.setVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET,
+ FhirResourceValues.create(bundleDecrypted));
}
private String getSendingOrganizationIdentifier()
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/process/projectathon/data_transfer/service/DeleteData.java
similarity index 65%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DeleteData.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/DeleteData.java
index adaf03b..c504bb3 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/process/projectathon/data_transfer/service/DeleteData.java
@@ -1,7 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
-
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.service;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
@@ -14,6 +11,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+
public class DeleteData extends AbstractServiceDelegate
{
private static final Logger logger = LoggerFactory.getLogger(DeleteData.class);
@@ -27,15 +26,16 @@ public DeleteData(FhirWebserviceClientProvider clientProvider, TaskHelper taskHe
@Override
protected void doExecute(DelegateExecution execution)
{
- String projectIdentifier = (String) execution.getVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER);
- IdType binaryId = new IdType((String) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE));
+ String projectIdentifier = (String) execution
+ .getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER);
+ IdType binaryId = new IdType(
+ (String) execution.getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE));
+ deletePermanently(binaryId);
logger.info(
- "Permanently deleting encrypted Binary with id='{}' provided for project-identifier='{}' "
+ "Permanently deleted encrypted Binary with id='{}' provided for project-identifier='{}' "
+ "referenced in Task with id='{}'...",
binaryId.getValue(), projectIdentifier, getLeadingTaskFromExecutionVariables().getId());
-
- deletePermanently(binaryId);
}
private void deletePermanently(IdType 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/process/projectathon/data_transfer/service/DownloadData.java
similarity index 78%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DownloadData.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/DownloadData.java
index db3ef78..98df07b 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/process/projectathon/data_transfer/service/DownloadData.java
@@ -1,17 +1,14 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.service;
import static java.util.stream.Collectors.toList;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_DATA_SET_REFERENCE;
-
import java.io.InputStream;
import java.util.List;
import javax.ws.rs.core.MediaType;
import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.camunda.bpm.engine.variable.Variables;
import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper;
import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
@@ -23,6 +20,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+
public class DownloadData extends AbstractServiceDelegate
{
private static final Logger logger = LoggerFactory.getLogger(DownloadData.class);
@@ -42,14 +41,15 @@ protected void doExecute(DelegateExecution execution) throws Exception
logger.info("Downloading Binary with id='{}'...", dataSetReference.getValue());
byte[] bundleEncrypted = readDataSet(dataSetReference);
- execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED, bundleEncrypted);
+ execution.setVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED,
+ Variables.byteArrayValue(bundleEncrypted));
}
private IdType getDataSetReference(Task task)
{
List dataSetReferences = getTaskHelper()
- .getInputParameterReferenceValues(task, CODESYSTEM_MII_DATA_TRANSFER,
- CODESYSTEM_MII_DATA_TRANSFER_VALUE_DATA_SET_REFERENCE)
+ .getInputParameterReferenceValues(task, ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER,
+ ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_DATA_SET_REFERENCE)
.filter(Reference::hasReference).map(Reference::getReference).collect(toList());
if (dataSetReferences.size() < 1)
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/process/projectathon/data_transfer/service/EncryptData.java
similarity index 82%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/EncryptData.java
index 97ce0a5..31cd17b 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/process/projectathon/data_transfer/service/EncryptData.java
@@ -1,14 +1,9 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.service;
import static java.util.stream.Collectors.toList;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER;
-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_DATA_SET_ENCRYPTED;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY;
-import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_ORGANIZATION_TYPE;
-import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_ORGANIZATION_TYPE_VALUE_COS;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_ORGANIZATION_ROLE;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_ORGANIZATION_ROLE_VALUE_COS;
import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER_MEDICAL_INFORMATICS_INITIATIVE_CONSORTIUM;
import java.nio.charset.StandardCharsets;
@@ -22,6 +17,7 @@
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.camunda.bpm.engine.variable.Variables;
import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper;
import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
@@ -37,8 +33,9 @@
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.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.crypto.KeyProvider;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.crypto.RsaAesGcmUtil;
public class EncryptData extends AbstractServiceDelegate implements InitializingBean
{
@@ -70,23 +67,24 @@ public void afterPropertiesSet() throws Exception
protected void doExecute(DelegateExecution execution)
{
String coordinatingSiteIdentifier = (String) execution
- .getVariable(BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER);
+ .getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER);
String localOrganizationIdentifier = organizationProvider.getLocalIdentifierValue();
- Bundle toEncrypt = (Bundle) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET);
+ Bundle toEncrypt = (Bundle) execution.getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET);
PublicKey publicKey = readPublicKey(coordinatingSiteIdentifier);
byte[] encrypted = encrypt(publicKey, toEncrypt, localOrganizationIdentifier, coordinatingSiteIdentifier);
- execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED, encrypted);
+ execution.setVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED,
+ Variables.byteArrayValue(encrypted));
}
private PublicKey readPublicKey(String coordinatingSiteIdentifier)
{
String url = getEndpointUrl(coordinatingSiteIdentifier);
Bundle searchBundle = getFhirWebserviceClientProvider().getWebserviceClient(url).search(Bundle.class,
- Map.of("identifier", Collections.singletonList(
- CODESYSTEM_MII_CRYPTOGRAPHY + "|" + CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY)));
+ Map.of("identifier", Collections.singletonList(ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY + "|"
+ + ConstantsDataTransfer.CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY)));
if (searchBundle.getTotal() != 1 && searchBundle.getEntryFirstRep().getResource() instanceof Bundle)
throw new IllegalStateException("Could not find PublicKey Bundle of organization with identifier='"
@@ -111,7 +109,7 @@ private String getEndpointUrl(String identifier)
{
return endpointProvider.getFirstConsortiumEndpointAdress(
NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER_MEDICAL_INFORMATICS_INITIATIVE_CONSORTIUM,
- CODESYSTEM_HIGHMED_ORGANIZATION_TYPE, CODESYSTEM_HIGHMED_ORGANIZATION_TYPE_VALUE_COS, identifier).get();
+ CODESYSTEM_HIGHMED_ORGANIZATION_ROLE, CODESYSTEM_HIGHMED_ORGANIZATION_ROLE_VALUE_COS, identifier).get();
}
private DocumentReference getDocumentReference(Bundle bundle)
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/InsertData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/InsertData.java
similarity index 69%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/InsertData.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/InsertData.java
index fb4e531..92358ec 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/InsertData.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/InsertData.java
@@ -1,11 +1,7 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.service;
import static java.util.stream.Collectors.toList;
-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.CODESYSTEM_MII_DATA_TRANSFER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_DOCUMENT_REFERENCE_LOCATION;
-
import java.util.List;
import java.util.Objects;
@@ -15,14 +11,15 @@
import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
import org.highmed.dsf.fhir.task.TaskHelper;
import org.hl7.fhir.r4.model.Bundle;
-import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.ResourceType;
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.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.processes.kds.client.KdsClientFactory;
public class InsertData extends AbstractServiceDelegate
{
@@ -52,9 +49,9 @@ public void afterPropertiesSet() throws Exception
@Override
protected void doExecute(DelegateExecution execution)
{
- Bundle bundle = (Bundle) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET);
+ Bundle bundle = (Bundle) execution.getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET);
- Bundle stored = kdsClientFactory.getKdsClient().getFhirClient().storeBundle(bundle);
+ Bundle stored = kdsClientFactory.getKdsClient().executeTransactionBundle(bundle);
List idsOfCreatedResources = stored.getEntry().stream().filter(Bundle.BundleEntryComponent::hasResponse)
.map(Bundle.BundleEntryComponent::getResponse).map(Bundle.BundleEntryResponseComponent::getLocation)
@@ -82,8 +79,9 @@ private void toLogMessage(IdType idType)
private void addOutputToLeadingTask(IdType id)
{
- getLeadingTaskFromExecutionVariables().addOutput().setValue(new CanonicalType(id.getValue())).getType()
- .addCoding().setSystem(CODESYSTEM_MII_DATA_TRANSFER)
- .setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_DOCUMENT_REFERENCE_LOCATION);
+ getLeadingTaskFromExecutionVariables().addOutput()
+ .setValue(new Reference(id.getValue()).setType(id.getResourceType())).getType().addCoding()
+ .setSystem(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER)
+ .setCode(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_DOCUMENT_REFERENCE_LOCATION);
}
}
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/process/projectathon/data_transfer/service/ReadData.java
similarity index 62%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/ReadData.java
index 2b406fa..52dc4d7 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/process/projectathon/data_transfer/service/ReadData.java
@@ -1,21 +1,13 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.service;
import static java.util.stream.Collectors.toList;
-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_COORDINATING_SITE_IDENTIFIER;
-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.CODESYSTEM_MII_DATA_TRANSFER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER;
-
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.camunda.bpm.engine.variable.Variables;
import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper;
import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
@@ -33,8 +25,8 @@
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;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.processes.kds.client.KdsClientFactory;
public class ReadData extends AbstractServiceDelegate
{
@@ -69,26 +61,27 @@ protected void doExecute(DelegateExecution execution)
String coordinatingSiteIdentifier = getCoordinatingSiteIdentifier(task);
DocumentReference documentReference = readDocumentReference(projectIdentifier, task.getId());
- LoggingHelper.logDebugResource("Read DocumentReference", documentReference);
-
Binary binary = readBinary(documentReference, task.getId());
- LoggingHelper.logDebugBinary("Read Binary", binary);
- execution.setVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER, projectIdentifier);
- execution.setVariable(BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER, coordinatingSiteIdentifier);
- execution.setVariable(BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE, FhirResourceValues.create(documentReference));
- execution.setVariable(BPMN_EXECUTION_VARIABLE_BINARY, FhirResourceValues.create(binary));
+ execution.setVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER,
+ Variables.stringValue(projectIdentifier));
+ execution.setVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER,
+ Variables.stringValue(coordinatingSiteIdentifier));
+ execution.setVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE,
+ FhirResourceValues.create(documentReference));
+ execution.setVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BINARY, FhirResourceValues.create(binary));
}
private String getProjectIdentifier(Task task)
{
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())))
+ .anyMatch(c -> ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER.equals(c.getSystem())
+ && ConstantsDataTransfer.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());
+ .filter(i -> ConstantsDataTransfer.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() + "'");
@@ -103,8 +96,8 @@ private String getProjectIdentifier(Task task)
private String getCoordinatingSiteIdentifier(Task task)
{
return getTaskHelper()
- .getFirstInputParameterReferenceValue(task, CODESYSTEM_MII_DATA_TRANSFER,
- CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER)
+ .getFirstInputParameterReferenceValue(task, ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER,
+ ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER)
.orElseThrow(() -> new IllegalArgumentException(
"No coordinating site identifier present in task, this should have been caught by resource validation"))
.getIdentifier().getValue();
@@ -112,10 +105,10 @@ private String getCoordinatingSiteIdentifier(Task task)
private DocumentReference readDocumentReference(String projectIdentifier, String taskId)
{
- List documentReferences = kdsClientFactory.getKdsClient().getFhirClient()
- .searchDocumentReferences(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER, projectIdentifier).getEntry().stream()
- .map(Bundle.BundleEntryComponent::getResource).filter(r -> r instanceof DocumentReference)
- .map(r -> ((DocumentReference) r)).collect(toList());
+ List documentReferences = kdsClientFactory.getKdsClient()
+ .searchDocumentReferences(ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER, projectIdentifier)
+ .getEntry().stream().map(Bundle.BundleEntryComponent::getResource)
+ .filter(r -> r instanceof DocumentReference).map(r -> ((DocumentReference) r)).collect(toList());
if (documentReferences.size() < 1)
throw new IllegalArgumentException("Could not find any DocumentReference for project-identifier='"
@@ -149,10 +142,6 @@ private Binary readBinary(DocumentReference documentReference, String taskId)
if (!validBinaryUrl(urls.get(0)))
{
- logger.warn(
- "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");
@@ -175,6 +164,6 @@ private boolean validBinaryUrl(String url)
private Binary readBinary(String url)
{
- return kdsClientFactory.getKdsClient().getFhirClient().readBinary(url);
+ return kdsClientFactory.getKdsClient().readBinary(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/process/projectathon/data_transfer/service/StoreData.java
similarity index 65%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/StoreData.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/StoreData.java
index 99624ac..fa890a8 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/process/projectathon/data_transfer/service/StoreData.java
@@ -1,12 +1,9 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.service;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER;
import static org.highmed.dsf.bpe.ConstantsBase.BPMN_EXECUTION_VARIABLE_TARGET;
-import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_ORGANIZATION_TYPE;
-import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_ORGANIZATION_TYPE_VALUE_COS;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_ORGANIZATION_ROLE;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_ORGANIZATION_ROLE_VALUE_COS;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ENDPOINT_IDENTIFIER;
import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER_MEDICAL_INFORMATICS_INITIATIVE_CONSORTIUM;
@@ -15,6 +12,7 @@
import javax.ws.rs.core.MediaType;
import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.camunda.bpm.engine.variable.Variables;
import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper;
import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider;
@@ -23,26 +21,31 @@
import org.highmed.dsf.fhir.variables.Target;
import org.highmed.dsf.fhir.variables.TargetValues;
import org.hl7.fhir.r4.model.Binary;
+import org.hl7.fhir.r4.model.Endpoint;
import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.ResourceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.processes.kds.client.logging.DataLogger;
public class StoreData extends AbstractServiceDelegate
{
private static final Logger logger = LoggerFactory.getLogger(StoreData.class);
private final EndpointProvider endpointProvider;
+ private final DataLogger dataLogger;
public StoreData(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
- ReadAccessHelper readAccessHelper, EndpointProvider endpointProvider)
+ ReadAccessHelper readAccessHelper, EndpointProvider endpointProvider, DataLogger dataLogger)
{
super(clientProvider, taskHelper, readAccessHelper);
this.endpointProvider = endpointProvider;
+ this.dataLogger = dataLogger;
}
@Override
@@ -51,15 +54,18 @@ public void afterPropertiesSet() throws Exception
super.afterPropertiesSet();
Objects.requireNonNull(endpointProvider, "endpointProvider");
+ Objects.requireNonNull(dataLogger, "dataLogger");
}
@Override
protected void doExecute(DelegateExecution execution)
{
- byte[] bundleEncrypted = (byte[]) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED);
+ byte[] bundleEncrypted = (byte[]) execution
+ .getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED);
String coordinatingSiteIdentifier = (String) execution
- .getVariable(BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER);
- String projectIdentifier = (String) execution.getVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER);
+ .getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER);
+ String projectIdentifier = (String) execution
+ .getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER);
Binary binary = createBinary(bundleEncrypted, coordinatingSiteIdentifier);
String binaryId = storeBinary(binary);
@@ -69,7 +75,8 @@ protected void doExecute(DelegateExecution execution)
Target target = createTarget(coordinatingSiteIdentifier);
- execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE, binaryId);
+ execution.setVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE,
+ Variables.stringValue(binaryId));
execution.setVariable(BPMN_EXECUTION_VARIABLE_TARGET, TargetValues.create(target));
}
@@ -81,7 +88,7 @@ private Binary createBinary(byte[] content, String coordinatingSiteIdentifier)
Binary binary = new Binary().setContentType(MediaType.APPLICATION_OCTET_STREAM)
.setSecurityContext(securityContext).setData(content);
- LoggingHelper.logDebugBinary("Created Binary", binary);
+ dataLogger.logResource("Encrypted Binary", binary);
return binary;
}
@@ -100,14 +107,22 @@ private IdType createBinaryResource(Binary binary)
private Target createTarget(String coordinatingSiteIdentifier)
{
- String endpointUrl = getEndpointUrl(coordinatingSiteIdentifier);
- return Target.createUniDirectionalTarget(coordinatingSiteIdentifier, endpointUrl);
+ Endpoint endpoint = getEndpoint(coordinatingSiteIdentifier);
+ return Target.createUniDirectionalTarget(coordinatingSiteIdentifier, getEndpointIdentifierValue(endpoint),
+ endpoint.getAddress());
}
- private String getEndpointUrl(String identifier)
+ private Endpoint getEndpoint(String identifier)
{
- return endpointProvider.getFirstConsortiumEndpointAdress(
+ return endpointProvider.getFirstConsortiumEndpoint(
NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER_MEDICAL_INFORMATICS_INITIATIVE_CONSORTIUM,
- CODESYSTEM_HIGHMED_ORGANIZATION_TYPE, CODESYSTEM_HIGHMED_ORGANIZATION_TYPE_VALUE_COS, identifier).get();
+ CODESYSTEM_HIGHMED_ORGANIZATION_ROLE, CODESYSTEM_HIGHMED_ORGANIZATION_ROLE_VALUE_COS, identifier).get();
+ }
+
+ private String getEndpointIdentifierValue(Endpoint endpoint)
+ {
+ return endpoint.getIdentifier().stream()
+ .filter(i -> NAMINGSYSTEM_HIGHMED_ENDPOINT_IDENTIFIER.equals(i.getSystem())).findFirst()
+ .map(Identifier::getValue).get();
}
}
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/process/projectathon/data_transfer/service/ValidateDataCos.java
similarity index 78%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/ValidateDataCos.java
index 91edf38..5d75c68 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/process/projectathon/data_transfer/service/ValidateDataCos.java
@@ -1,12 +1,11 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.service;
import static java.util.stream.Collectors.toList;
-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.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER;
import static org.hl7.fhir.r4.model.Bundle.BundleType.TRANSACTION;
import java.util.List;
+import java.util.Objects;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate;
@@ -20,20 +19,32 @@
import org.hl7.fhir.r4.model.Reference;
import org.springframework.beans.factory.InitializingBean;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.MimeTypeHelper;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.util.MimeTypeHelper;
public class ValidateDataCos extends AbstractServiceDelegate implements InitializingBean
{
+ private final MimeTypeHelper mimeTypeHelper;
+
public ValidateDataCos(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
- ReadAccessHelper readAccessHelper)
+ ReadAccessHelper readAccessHelper, MimeTypeHelper mimeTypeHelper)
{
super(clientProvider, taskHelper, readAccessHelper);
+
+ this.mimeTypeHelper = mimeTypeHelper;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+ Objects.requireNonNull(mimeTypeHelper, "mimeTypeHelper");
}
@Override
protected void doExecute(DelegateExecution execution)
{
- Bundle bundle = (Bundle) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET);
+ Bundle bundle = (Bundle) execution.getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET);
Bundle.BundleType type = bundle.getType();
if (!TRANSACTION.equals(type))
@@ -70,7 +81,7 @@ protected void doExecute(DelegateExecution execution)
long countMi = documentReferences.stream().filter(DocumentReference::hasMasterIdentifier)
.map(DocumentReference::getMasterIdentifier)
- .filter(mi -> NAMINGSYSTEM_MII_PROJECT_IDENTIFIER.equals(mi.getSystem())).count();
+ .filter(mi -> ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER.equals(mi.getSystem())).count();
if (countMi != 1)
{
throw new RuntimeException("DocumentReference contains < 1 or > 1 of projectIdentifiers (" + countMi + ")");
@@ -87,6 +98,6 @@ protected void doExecute(DelegateExecution execution)
byte[] dataB = binaries.get(0).getData();
String mimeTypeB = binaries.get(0).getContentType();
- MimeTypeHelper.validate(dataB, mimeTypeB);
+ 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/process/projectathon/data_transfer/service/ValidateDataDic.java
similarity index 66%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/service/ValidateDataDic.java
index eab4184..e1ce51c 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/process/projectathon/data_transfer/service/ValidateDataDic.java
@@ -1,6 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.service;
-
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BINARY;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.service;
import java.util.Objects;
@@ -13,18 +11,21 @@
import org.hl7.fhir.r4.model.Binary;
import org.springframework.beans.factory.InitializingBean;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.MimeTypeHelper;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.util.MimeTypeHelper;
public class ValidateDataDic extends AbstractServiceDelegate implements InitializingBean
{
private final OrganizationProvider organizationProvider;
+ private final MimeTypeHelper mimeTypeHelper;
public ValidateDataDic(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper,
- ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider)
+ ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, MimeTypeHelper mimeTypeHelper)
{
super(clientProvider, taskHelper, readAccessHelper);
this.organizationProvider = organizationProvider;
+ this.mimeTypeHelper = mimeTypeHelper;
}
@Override
@@ -33,16 +34,17 @@ public void afterPropertiesSet() throws Exception
super.afterPropertiesSet();
Objects.requireNonNull(organizationProvider, "organizationProvider");
+ Objects.requireNonNull(mimeTypeHelper, "mimeTypeHelper");
}
@Override
protected void doExecute(DelegateExecution execution)
{
- Binary binary = (Binary) execution.getVariable(BPMN_EXECUTION_VARIABLE_BINARY);
+ Binary binary = (Binary) execution.getVariable(ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BINARY);
String mimeTypeBinary = binary.getContentType();
byte[] dataBinary = binary.getData();
- MimeTypeHelper.validate(dataBinary, mimeTypeBinary);
+ mimeTypeHelper.validate(dataBinary, mimeTypeBinary);
}
}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/spring/config/TransferDataConfig.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/spring/config/TransferDataConfig.java
new file mode 100644
index 0000000..6b245df
--- /dev/null
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/spring/config/TransferDataConfig.java
@@ -0,0 +1,157 @@
+package de.medizininformatik_initiative.process.projectathon.data_transfer.spring.config;
+
+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.highmed.dsf.tools.generator.ProcessDocumentation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.crypto.KeyProvider;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.crypto.KeyProviderImpl;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.message.StartReceiveProcess;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.CreateBundle;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.DecryptData;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.DeleteData;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.DownloadData;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.EncryptData;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.InsertData;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.ReadData;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.StoreData;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.ValidateDataCos;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.service.ValidateDataDic;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.util.MimeTypeHelper;
+import de.medizininformatik_initiative.processes.kds.client.spring.config.PropertiesConfig;
+
+@Configuration
+@ComponentScan(basePackages = "de.medizininformatik_initiative")
+public class TransferDataConfig
+{
+ @Autowired
+ private FhirWebserviceClientProvider fhirClientProvider;
+
+ @Autowired
+ private TaskHelper taskHelper;
+
+ @Autowired
+ private ReadAccessHelper readAccessHelper;
+
+ @Autowired
+ private OrganizationProvider organizationProvider;
+
+ @Autowired
+ private EndpointProvider endpointProvider;
+
+ @Autowired
+ private FhirContext fhirContext;
+
+ @Autowired
+ private PropertiesConfig kdsFhirClientConfig;
+
+ @ProcessDocumentation(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;
+
+ @ProcessDocumentation(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;
+
+ @Bean
+ public MimeTypeHelper mimeTypeHelper()
+ {
+ return new MimeTypeHelper();
+ }
+
+ // projectathonDataSend
+
+ @Bean
+ public ReadData readData()
+ {
+ return new ReadData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext,
+ kdsFhirClientConfig.kdsClientFactory());
+ }
+
+ @Bean
+ public ValidateDataDic validateDataDic()
+ {
+ return new ValidateDataDic(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider,
+ mimeTypeHelper());
+ }
+
+ @Bean
+ public CreateBundle createBundle()
+ {
+ return new CreateBundle(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider,
+ kdsFhirClientConfig.dataLogger());
+ }
+
+ @Bean
+ public EncryptData encryptData()
+ {
+ return new EncryptData(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider,
+ endpointProvider);
+ }
+
+ @Bean
+ public StoreData storeData()
+ {
+ return new StoreData(fhirClientProvider, taskHelper, readAccessHelper, endpointProvider,
+ kdsFhirClientConfig.dataLogger());
+ }
+
+ @Bean
+ public StartReceiveProcess startReceiveProcess()
+ {
+ return new StartReceiveProcess(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider,
+ fhirContext);
+ }
+
+ @Bean
+ public DeleteData deleteData()
+ {
+ return new DeleteData(fhirClientProvider, taskHelper, readAccessHelper);
+ }
+
+ // projectathonDataReceive
+
+ @Bean
+ public DownloadData downloadData()
+ {
+ return new DownloadData(fhirClientProvider, taskHelper, readAccessHelper);
+ }
+
+ @Bean
+ public KeyProvider keyProvider()
+ {
+ return KeyProviderImpl.fromFiles(cosPrivateKeyFile, cosPublicKeyFile, fhirClientProvider, organizationProvider,
+ readAccessHelper, kdsFhirClientConfig.dataLogger());
+ }
+
+ @Bean
+ public DecryptData decryptData()
+ {
+ return new DecryptData(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider, keyProvider(),
+ kdsFhirClientConfig.dataLogger());
+ }
+
+ @Bean
+ public ValidateDataCos validateDataCos()
+ {
+ return new ValidateDataCos(fhirClientProvider, taskHelper, readAccessHelper, mimeTypeHelper());
+ }
+
+ @Bean
+ public InsertData insertData()
+ {
+ return new InsertData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext,
+ kdsFhirClientConfig.kdsClientFactory());
+ }
+}
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/process/projectathon/data_transfer/util/MimeTypeHelper.java
similarity index 93%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java
rename to mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/process/projectathon/data_transfer/util/MimeTypeHelper.java
index 432568f..7495eb6 100644
--- 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/process/projectathon/data_transfer/util/MimeTypeHelper.java
@@ -1,4 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.util;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.util;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.io.TikaInputStream;
@@ -23,7 +23,7 @@ public class MimeTypeHelper
* @throws RuntimeException
* if the detected and the declared base mime-type do not match
*/
- public static void validate(byte[] data, String declared)
+ public void validate(byte[] data, String declared)
{
MediaType declaredMimeType = MediaType.parse(declared);
MediaType detectedMimeType = MediaType.EMPTY;
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClient.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClient.java
deleted file mode 100644
index cba3193..0000000
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClient.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client;
-
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.rest.client.api.IGenericClient;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir.KdsFhirClient;
-
-public interface KdsClient
-{
- FhirContext getFhirContext();
-
- void testConnection();
-
- KdsFhirClient getFhirClient();
-
- IGenericClient getGenericFhirClient();
-
- String getLocalIdentifierValue();
-
- String getFhirBaseUrl();
-}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientStub.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientStub.java
deleted file mode 100644
index 9408c2a..0000000
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientStub.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.rest.client.api.IGenericClient;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir.KdsFhirClient;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir.KdsFhirClientStub;
-
-public class KdsClientStub implements KdsClient
-{
- private static final Logger logger = LoggerFactory.getLogger(KdsClientStub.class);
-
- private final FhirContext fhirContext;
- private final String localIdentifierValue;
- private final String kdsServerBase;
-
- KdsClientStub(FhirContext fhirContext, String localIdentifierValue)
- {
- this.fhirContext = fhirContext;
- this.localIdentifierValue = localIdentifierValue;
- this.kdsServerBase = "http://foo.bar/fhir";
- }
-
- @Override
- public void testConnection()
- {
- logger.warn("Stub implementation, no connection test performed");
- }
-
- @Override
- public KdsFhirClient getFhirClient()
- {
- return new KdsFhirClientStub(this);
- }
-
- @Override
- public FhirContext getFhirContext()
- {
- return fhirContext;
- }
-
- @Override
- public IGenericClient getGenericFhirClient()
- {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public String getLocalIdentifierValue()
- {
- return localIdentifierValue;
- }
-
- @Override
- public String getFhirBaseUrl()
- {
- return kdsServerBase;
- }
-}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClient.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClient.java
deleted file mode 100644
index a679885..0000000
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClient.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir;
-
-import org.hl7.fhir.r4.model.Binary;
-import org.hl7.fhir.r4.model.Bundle;
-
-public interface KdsFhirClient
-{
- Bundle searchDocumentReferences(String system, String code);
-
- Binary readBinary(String url);
-
- Bundle storeBundle(Bundle toStore);
-}
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
deleted file mode 100644
index 0dd29a4..0000000
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientImpl.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir;
-
-import static ca.uhn.fhir.rest.api.Constants.HEADER_PREFER;
-
-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.IdType;
-
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.KdsClient;
-
-public class KdsFhirClientImpl implements KdsFhirClient
-{
- private KdsClient kdsClient;
-
- public KdsFhirClientImpl(KdsClient kdsClient)
- {
- this.kdsClient = kdsClient;
- }
-
- @Override
- public Bundle searchDocumentReferences(String system, String code)
- {
- return kdsClient.getGenericFhirClient().search().forResource(DocumentReference.class)
- .where(DocumentReference.IDENTIFIER.exactly().systemAndIdentifier(system, code))
- .returnBundle(Bundle.class).execute();
- }
-
- @Override
- public Binary readBinary(String url)
- {
- return kdsClient.getGenericFhirClient().read().resource(Binary.class).withId(new IdType(url).getIdPart())
- .execute();
- }
-
- @Override
- public Bundle storeBundle(Bundle toStore)
- {
- return kdsClient.getGenericFhirClient().transaction().withBundle(toStore)
- .withAdditionalHeader(HEADER_PREFER, "handling=strict").execute();
- }
-}
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
deleted file mode 100644
index b9cf338..0000000
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java
+++ /dev/null
@@ -1,248 +0,0 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.spring.config;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-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.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import ca.uhn.fhir.context.FhirContext;
-import de.medizininformatik_initiative.processes.documentation.generator.Documentation;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.KdsClientFactory;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir.KdsFhirClient;
-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;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.EncryptData;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.InsertData;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.ReadData;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.StoreData;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.ValidateDataCos;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.ValidateDataDic;
-
-@Configuration
-public class TransferDataConfig
-{
- @Autowired
- private FhirWebserviceClientProvider fhirClientProvider;
-
- @Autowired
- private TaskHelper taskHelper;
-
- @Autowired
- private ReadAccessHelper readAccessHelper;
-
- @Autowired
- private OrganizationProvider organizationProvider;
-
- @Autowired
- private EndpointProvider endpointProvider;
-
- @Autowired
- private FhirContext fhirContext;
-
- @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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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;
-
- @Value("${org.highmed.dsf.bpe.fhir.server.organization.identifier.value}")
- private String localIdentifierValue;
-
- @Bean
- @SuppressWarnings("unchecked")
- public KdsClientFactory kdsClientFactory()
- {
- Path trustStorePath = checkExists(fhirStoreTrustStore);
- Path certificatePath = checkExists(fhirStoreCertificate);
- Path privateKeyPath = checkExists(fhirStorePrivateKey);
-
- try
- {
- return new KdsClientFactory(trustStorePath, certificatePath, privateKeyPath, fhirStorePrivateKeyPassword,
- fhirStoreConnectTimeout, fhirStoreSocketTimeout, fhirStoreConnectionRequestTimeout,
- fhirStoreBaseUrl, fhirStoreUsername, fhirStorePassword, fhirStoreBearerToken, fhirStoreProxyUrl,
- fhirStoreProxyUsername, fhirStoreProxyPassword, fhirStoreHapiClientVerbose, fhirContext,
- (Class) Class.forName(fhirStoreClientClass), localIdentifierValue);
- }
- catch (ClassNotFoundException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- private Path checkExists(String file)
- {
- if (file == null)
- return null;
- else
- {
- Path path = Paths.get(file);
-
- if (!Files.isReadable(path))
- throw new RuntimeException(path.toString() + " not readable");
-
- return path;
- }
- }
-
- // projectathonDataSend
-
- @Bean
- public ReadData readData()
- {
- return new ReadData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext, kdsClientFactory());
- }
-
- @Bean
- 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, organizationProvider,
- endpointProvider);
- }
-
- @Bean
- public StoreData storeData()
- {
- return new StoreData(fhirClientProvider, taskHelper, readAccessHelper, endpointProvider);
- }
-
- @Bean
- public StartReceiveProcess startReceiveProcess()
- {
- return new StartReceiveProcess(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider,
- fhirContext);
- }
-
- @Bean
- public DeleteData deleteData()
- {
- return new DeleteData(fhirClientProvider, taskHelper, readAccessHelper);
- }
-
- // projectathonDataReceive
-
- @Bean
- public DownloadData downloadData()
- {
- return new DownloadData(fhirClientProvider, taskHelper, readAccessHelper);
- }
-
- @Bean
- public KeyProvider keyProvider()
- {
- return KeyProviderImpl.fromFiles(cosPrivateKeyFile, cosPublicKeyFile, fhirClientProvider, organizationProvider,
- readAccessHelper);
- }
-
- @Bean
- public DecryptData decryptData()
- {
- return new DecryptData(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider, keyProvider());
- }
-
- @Bean
- public ValidateDataCos validateDataCos()
- {
- return new ValidateDataCos(fhirClientProvider, taskHelper, readAccessHelper);
- }
-
- @Bean
- public InsertData insertData()
- {
- 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
deleted file mode 100644
index 4bcca76..0000000
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/LoggingHelper.java
+++ /dev/null
@@ -1,50 +0,0 @@
-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/resources/META-INF/services/org.highmed.dsf.bpe.ProcessPluginDefinition b/mii-dsf-process-projectathon-data-transfer/src/main/resources/META-INF/services/org.highmed.dsf.bpe.ProcessPluginDefinition
index b52f16e..c3ce429 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/META-INF/services/org.highmed.dsf.bpe.ProcessPluginDefinition
+++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/META-INF/services/org.highmed.dsf.bpe.ProcessPluginDefinition
@@ -1 +1 @@
-de.medizininformatik_initiative.processes.projectathon.data_transfer.DataTransferProcessPluginDefinition
\ No newline at end of file
+de.medizininformatik_initiative.process.projectathon.data_transfer.DataTransferProcessPluginDefinition
\ No newline at end of file
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 a89793b..80ad982 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
@@ -1,17 +1,17 @@
-
-
+
+
Flow_1gyqorb
-
+
Flow_1gyqorb
Flow_064nbas
-
+
Flow_064nbas
Flow_1c3t0x1
@@ -19,12 +19,12 @@
Flow_1w6vljw
-
+
Flow_0j6v09z
Flow_1w6vljw
-
+
Flow_1c3t0x1
Flow_0j6v09z
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 7484c77..b765144 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,26 +1,26 @@
-
-
+
+
Flow_0kkjyst
-
+
Flow_0kkjyst
Flow_0yamo5r
-
+
Flow_0yamo5r
Flow_0zrvqk8
-
+
Flow_05qlnk4
Flow_15vmy2h
-
+
Flow_15vmy2h
Flow_109e2pt
@@ -39,31 +39,31 @@
- http://medizininformatik-initiative.de/fhir/StructureDefinition/task-start-data-receive|0.1.0
- http://medizininformatik-initiative.de/bpe/Process/dataReceive/0.1.0
+ http://medizininformatik-initiative.de/fhir/StructureDefinition/task-start-data-receive|#{version}
+ http://medizininformatik-initiative.de/bpe/Process/dataReceive/#{version}
startDataReceiveMii
Flow_109e2pt
Flow_1yhho1t
-
+
- http://medizininformatik-initiative.de/bpe/Process/dataReceive/0.1.0
+ http://medizininformatik-initiative.de/bpe/Process/dataReceive/#{version}
startDataReceiveMii
- http://medizininformatik-initiative.de/fhir/StructureDefinition/task-start-data-receive|0.1.0
+ http://medizininformatik-initiative.de/fhir/StructureDefinition/task-start-data-receive|#{version}
Flow_0phc02z
-
+
Flow_1pzxejf
Flow_0phc02z
-
+
Flow_0zrvqk8
Flow_05qlnk4
@@ -72,6 +72,10 @@
+
+
+
+
@@ -104,10 +108,6 @@
-
-
-
-
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 85eacc5..214d4df 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
@@ -12,7 +12,7 @@
+ value="http://medizininformatik-initiative.de/fhir/StructureDefinition/task-start-data-receive|#{version}" />
@@ -25,7 +25,7 @@
-
+
@@ -45,7 +45,7 @@
-
+
@@ -65,7 +65,7 @@
-
+
@@ -78,14 +78,15 @@
-
+
-
+
+
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 bf576a6..119e2d9 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
@@ -12,7 +12,7 @@
+ value="http://medizininformatik-initiative.de/fhir/StructureDefinition/task-start-data-send|#{version}" />
@@ -25,7 +25,7 @@
-
+
@@ -45,7 +45,7 @@
-
+
@@ -58,14 +58,15 @@
-
+
-
+
+
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 cb78a76..a77f4a0 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
@@ -7,13 +7,14 @@
-
+
-
+
+
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 f689247..4768500 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
@@ -7,13 +7,14 @@
-
+
-
+
+
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 24929aa..bf03188 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
@@ -9,7 +9,8 @@
-
+
+
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 676eb5c..a9636d6 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
@@ -1,129 +1,140 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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 a64e561..38cc158 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
@@ -7,12 +7,13 @@
-
+
-
+
+
@@ -22,7 +23,7 @@
-
+
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 37e4adb..5aa6fd6 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
@@ -7,13 +7,14 @@
-
+
-
+
+
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 695d390..b67cdd2 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
@@ -7,13 +7,14 @@
-
+
-
+
+
diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/bpe/DataTransferProcessPluginDefinitionTest.java b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/bpe/DataTransferProcessPluginDefinitionTest.java
new file mode 100644
index 0000000..bf337c6
--- /dev/null
+++ b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/bpe/DataTransferProcessPluginDefinitionTest.java
@@ -0,0 +1,36 @@
+package de.medizininformatik_initiative.process.projectathon.data_transfer.bpe;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.highmed.dsf.bpe.ProcessPluginDefinition;
+import org.highmed.dsf.fhir.resources.ResourceProvider;
+import org.junit.Test;
+import org.springframework.core.env.StandardEnvironment;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.DataTransferProcessPluginDefinition;
+
+public class DataTransferProcessPluginDefinitionTest
+{
+ @Test
+ public void testResourceLoading() throws Exception
+ {
+ ProcessPluginDefinition definition = new DataTransferProcessPluginDefinition();
+ ResourceProvider provider = definition.getResourceProvider(FhirContext.forR4(), getClass().getClassLoader(),
+ new StandardEnvironment());
+ assertNotNull(provider);
+
+ var send = provider.getResources(
+ ConstantsDataTransfer.PROCESS_NAME_FULL_DATA_SEND + "/" + DataTransferProcessPluginDefinition.VERSION,
+ s -> ResourceProvider.empty());
+ assertNotNull(send);
+ assertEquals(7, send.count());
+
+ var receive = provider.getResources(ConstantsDataTransfer.PROCESS_NAME_FULL_DATA_RECEIVE + "/"
+ + DataTransferProcessPluginDefinition.VERSION, s -> ResourceProvider.empty());
+ assertNotNull(receive);
+ assertEquals(7, receive.count());
+ }
+}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java
new file mode 100644
index 0000000..a8eddbf
--- /dev/null
+++ b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java
@@ -0,0 +1,64 @@
+package de.medizininformatik_initiative.process.projectathon.data_transfer.bpe.start;
+
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN;
+import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME;
+import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.highmed.dsf.bpe.start.ExampleStarter;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Identifier;
+import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.ResourceType;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.Task;
+import org.hl7.fhir.r4.model.Task.TaskIntent;
+import org.hl7.fhir.r4.model.Task.TaskStatus;
+
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+
+public class DataSendExampleStarter
+{
+ public static void main(String[] args) throws Exception
+ {
+ Task task = createTask();
+ ExampleStarter.forServer(args, "https://dic1/fhir").startWith(task);
+ }
+
+ private static Task createTask()
+ {
+ Task task = new Task();
+ task.setIdElement(new IdType("urn:uuid:" + UUID.randomUUID().toString()));
+
+ task.getMeta().addProfile(ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_SEND_AND_LATEST_VERSION);
+ task.setInstantiatesUri(ConstantsDataTransfer.PROFILE_MII_TASK_DATA_SEND_PROCESS_URI_AND_LATEST_VERSION);
+ task.setStatus(TaskStatus.REQUESTED);
+ task.setIntent(TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_DIC1");
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_DIC1");
+
+ task.addInput().setValue(new StringType(ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_SEND_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+
+ task.addInput()
+ .setValue(new Reference().setIdentifier(
+ new Identifier().setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_COS"))
+ .setType(ResourceType.Organization.name()))
+ .getType().addCoding().setSystem(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER)
+ .setCode(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER);
+
+ task.addInput()
+ .setValue(new Identifier().setSystem(ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER)
+ .setValue("Test_PROJECT"))
+ .getType().addCoding().setSystem(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER)
+ .setCode(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER);
+
+ return task;
+ }
+}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/ActivityDefinitionProfileTest.java b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/fhir/profile/ActivityDefinitionProfileTest.java
similarity index 59%
rename from mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/ActivityDefinitionProfileTest.java
rename to mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/fhir/profile/ActivityDefinitionProfileTest.java
index e2c4a36..3e72f09 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/ActivityDefinitionProfileTest.java
+++ b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/fhir/profile/ActivityDefinitionProfileTest.java
@@ -1,11 +1,8 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.fhir.profile;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.fhir.profile;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.DataTransferProcessPluginDefinition.VERSION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import java.io.InputStream;
-import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -22,13 +19,15 @@
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.ValidationResult;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.DataTransferProcessPluginDefinition;
public class ActivityDefinitionProfileTest
{
private static final Logger logger = LoggerFactory.getLogger(ActivityDefinitionProfileTest.class);
@ClassRule
- public static final ValidationSupportRule validationRule = new ValidationSupportRule(VERSION,
+ public static final ValidationSupportRule validationRule = new ValidationSupportRule(
+ DataTransferProcessPluginDefinition.VERSION, DataTransferProcessPluginDefinition.RELEASE_DATE,
Arrays.asList("highmed-activity-definition-0.5.0.xml", "highmed-extension-process-authorization-0.5.0.xml",
"highmed-extension-process-authorization-consortium-role-0.5.0.xml",
"highmed-extension-process-authorization-organization-0.5.0.xml",
@@ -50,40 +49,30 @@ public class ActivityDefinitionProfileTest
@Test
public void testDataSendValid() throws Exception
{
- try (InputStream in = Files
- .newInputStream(Paths.get("src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml")))
- {
- ActivityDefinition ad = validationRule.getFhirContext().newXmlParser()
- .parseResource(ActivityDefinition.class, in);
+ ActivityDefinition ad = validationRule.readActivityDefinition(
+ Paths.get("src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml"));
- ValidationResult result = resourceValidator.validate(ad);
- ValidationSupportRule.logValidationMessages(logger, result);
+ ValidationResult result = resourceValidator.validate(ad);
+ ValidationSupportRule.logValidationMessages(logger, result);
- assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
- || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
- assertTrue(
- processAuthorizationHelper.isValid(ad, taskProfile -> true, orgIdentifier -> true, role -> true));
- }
+ assertTrue(processAuthorizationHelper.isValid(ad, taskProfile -> true, orgIdentifier -> true, role -> true));
}
@Test
public void testDataReceiveValid() throws Exception
{
- try (InputStream in = Files.newInputStream(
- Paths.get("src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml")))
- {
- ActivityDefinition ad = validationRule.getFhirContext().newXmlParser()
- .parseResource(ActivityDefinition.class, in);
+ ActivityDefinition ad = validationRule.readActivityDefinition(
+ Paths.get("src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml"));
- ValidationResult result = resourceValidator.validate(ad);
- ValidationSupportRule.logValidationMessages(logger, result);
+ ValidationResult result = resourceValidator.validate(ad);
+ ValidationSupportRule.logValidationMessages(logger, result);
- assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
- || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
- assertTrue(
- processAuthorizationHelper.isValid(ad, taskProfile -> true, orgIdentifier -> true, role -> true));
- }
+ assertTrue(processAuthorizationHelper.isValid(ad, taskProfile -> true, orgIdentifier -> true, role -> true));
}
}
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/process/projectathon/data_transfer/fhir/profile/TaskProfileTest.java
similarity index 62%
rename from mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/TaskProfileTest.java
rename to mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/process/projectathon/data_transfer/fhir/profile/TaskProfileTest.java
index 5f9f263..2bed7e6 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/process/projectathon/data_transfer/fhir/profile/TaskProfileTest.java
@@ -1,17 +1,5 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.fhir.profile;
-
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_DATA_SET_REFERENCE;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.PROFILE_MII_TASK_DATA_RECEIVE_PROCESS_URI_AND_LATEST_VERSION;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.PROFILE_MII_TASK_DATA_SEND_PROCESS_URI_AND_LATEST_VERSION;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_RECEIVE;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_RECEIVE_MESSAGE_NAME;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_SEND;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_SEND_MESSAGE_NAME;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.DataTransferProcessPluginDefinition.VERSION;
+package de.medizininformatik_initiative.process.projectathon.data_transfer.fhir.profile;
+
import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN;
import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY;
import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME;
@@ -39,13 +27,16 @@
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.ValidationResult;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.ConstantsDataTransfer;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.DataTransferProcessPluginDefinition;
public class TaskProfileTest
{
private static final Logger logger = LoggerFactory.getLogger(TaskProfileTest.class);
@ClassRule
- public static final ValidationSupportRule validationRule = new ValidationSupportRule(VERSION,
+ public static final ValidationSupportRule validationRule = new ValidationSupportRule(
+ DataTransferProcessPluginDefinition.VERSION, DataTransferProcessPluginDefinition.RELEASE_DATE,
Arrays.asList("highmed-task-base-0.5.0.xml", "mii-projectathon-task-start-data-receive.xml",
"mii-projectathon-task-start-data-send.xml"),
Arrays.asList("highmed-read-access-tag-0.5.0.xml", "highmed-bpmn-message-0.5.0.xml",
@@ -93,8 +84,8 @@ public void testTaskStartDataSendValidWithBusinessKey() throws Exception
private Task createValidTaskStartDataSend()
{
Task task = new Task();
- task.getMeta().addProfile(PROFILE_MII_TASK_START_DATA_SEND);
- task.setInstantiatesUri(PROFILE_MII_TASK_DATA_SEND_PROCESS_URI_AND_LATEST_VERSION);
+ task.getMeta().addProfile(ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_SEND);
+ task.setInstantiatesUri(ConstantsDataTransfer.PROFILE_MII_TASK_DATA_SEND_PROCESS_URI_AND_LATEST_VERSION);
task.setStatus(TaskStatus.REQUESTED);
task.setIntent(TaskIntent.ORDER);
task.setAuthoredOn(new Date());
@@ -102,20 +93,22 @@ private Task createValidTaskStartDataSend()
.setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_DIC");
task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
.setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_DIC");
- task.addInput().setValue(new StringType(PROFILE_MII_TASK_START_DATA_SEND_MESSAGE_NAME)).getType().addCoding()
- .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+ task.addInput().setValue(new StringType(ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_SEND_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
task.addInput()
.setValue(new Reference().setIdentifier(
new Identifier().setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_COS"))
.setType(ResourceType.Organization.name()))
- .getType().addCoding().setSystem(CODESYSTEM_MII_DATA_TRANSFER)
- .setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER);
+ .getType().addCoding().setSystem(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER)
+ .setCode(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER);
task.addInput()
- .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);
+ .setValue(new Identifier().setSystem(ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER)
+ .setValue("Test_PROJECT"))
+ .getType().addCoding().setSystem(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER)
+ .setCode(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER);
return task;
}
@@ -136,8 +129,8 @@ public void testTaskStartDataReceiveValid()
private Task createValidTaskStartDataReceive()
{
Task task = new Task();
- task.getMeta().addProfile(PROFILE_MII_TASK_START_DATA_RECEIVE);
- task.setInstantiatesUri(PROFILE_MII_TASK_DATA_RECEIVE_PROCESS_URI_AND_LATEST_VERSION);
+ task.getMeta().addProfile(ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_RECEIVE);
+ task.setInstantiatesUri(ConstantsDataTransfer.PROFILE_MII_TASK_DATA_RECEIVE_PROCESS_URI_AND_LATEST_VERSION);
task.setStatus(TaskStatus.REQUESTED);
task.setIntent(TaskIntent.ORDER);
task.setAuthoredOn(new Date());
@@ -145,15 +138,16 @@ private Task createValidTaskStartDataReceive()
.setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_DIC");
task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
.setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_COS");
- task.addInput().setValue(new StringType(PROFILE_MII_TASK_START_DATA_RECEIVE_MESSAGE_NAME)).getType().addCoding()
- .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
+ task.addInput().setValue(new StringType(ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_RECEIVE_MESSAGE_NAME))
+ .getType().addCoding().setSystem(CODESYSTEM_HIGHMED_BPMN)
+ .setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding()
.setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY);
task.addInput()
.setValue(new Reference().setReference("https://dsf-dic.de/fhir/Binary/" + UUID.randomUUID().toString())
.setType(ResourceType.Binary.name()))
- .getType().addCoding().setSystem(CODESYSTEM_MII_DATA_TRANSFER)
- .setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_DATA_SET_REFERENCE);
+ .getType().addCoding().setSystem(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER)
+ .setCode(ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_DATA_SET_REFERENCE);
return task;
}
}
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
deleted file mode 100644
index 3b4e7f8..0000000
--- a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.bpe.start;
-
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.PROFILE_MII_TASK_DATA_SEND_PROCESS_URI_AND_LATEST_VERSION;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_SEND_AND_LATEST_VERSION;
-import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.PROFILE_MII_TASK_START_DATA_SEND_MESSAGE_NAME;
-import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN;
-import static org.highmed.dsf.bpe.ConstantsBase.CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME;
-import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
-
-import java.util.Date;
-import java.util.UUID;
-
-import org.highmed.dsf.bpe.start.ExampleStarter;
-import org.hl7.fhir.r4.model.IdType;
-import org.hl7.fhir.r4.model.Identifier;
-import org.hl7.fhir.r4.model.Reference;
-import org.hl7.fhir.r4.model.ResourceType;
-import org.hl7.fhir.r4.model.StringType;
-import org.hl7.fhir.r4.model.Task;
-import org.hl7.fhir.r4.model.Task.TaskIntent;
-import org.hl7.fhir.r4.model.Task.TaskStatus;
-
-public class DataSendExampleStarter
-{
- public static void main(String[] args) throws Exception
- {
- Task task = createTask();
- ExampleStarter.forServer(args, "https://dic/fhir").startWith(task);
- }
-
- private static Task createTask()
- {
- Task task = new Task();
- task.setIdElement(new IdType("urn:uuid:" + UUID.randomUUID().toString()));
-
- task.getMeta().addProfile(PROFILE_MII_TASK_START_DATA_SEND_AND_LATEST_VERSION);
- task.setInstantiatesUri(PROFILE_MII_TASK_DATA_SEND_PROCESS_URI_AND_LATEST_VERSION);
- task.setStatus(TaskStatus.REQUESTED);
- task.setIntent(TaskIntent.ORDER);
- task.setAuthoredOn(new Date());
- task.getRequester().setType(ResourceType.Organization.name()).getIdentifier()
- .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_DIC");
- task.getRestriction().addRecipient().setType(ResourceType.Organization.name()).getIdentifier()
- .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_DIC");
-
- task.addInput().setValue(new StringType(PROFILE_MII_TASK_START_DATA_SEND_MESSAGE_NAME)).getType().addCoding()
- .setSystem(CODESYSTEM_HIGHMED_BPMN).setCode(CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME);
-
- task.addInput()
- .setValue(new Reference().setIdentifier(
- new Identifier().setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue("Test_COS"))
- .setType(ResourceType.Organization.name()))
- .getType().addCoding().setSystem(CODESYSTEM_MII_DATA_TRANSFER)
- .setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER);
-
- task.addInput()
- .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);
-
- return task;
- }
-}
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 1f8ba0b..414c722 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
@@ -1,8 +1,8 @@
-
+
-
+
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 3c1d4ee..e9514d8 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
@@ -1,8 +1,8 @@
-
+
-
+
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 6b86da1..5bf3f69 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
@@ -1,8 +1,8 @@
-
+
-
+
diff --git a/mii-dsf-processes-docker-test-setup/README-Data-Transfer-Process.md b/mii-dsf-processes-docker-test-setup/README-Data-Transfer-Process.md
new file mode 100644
index 0000000..357a289
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/README-Data-Transfer-Process.md
@@ -0,0 +1,99 @@
+# Data Transfer Process: Testing using Docker Setup
+
+Build the project from the root directory of this repository by executing the following command.
+
+```sh
+mvn clean package
+```
+
+Add entries to your hosts file
+
+```
+127.0.0.1 dic1
+127.0.0.1 cos
+```
+
+*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 DIC1 HAPI FHIR Server
+
+```sh
+docker-compose up dic1-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:8082/fhir/
+
+Console 2: Start DIC1 DSF FHIR Server and wait till started
+
+```sh
+docker-compose up -d dic1-fhir && docker-compose logs -f dic1-fhir
+```
+
+Console 2: Disconnect from log output (Ctrl-C) if Server started
+Console 2: Start DIC1 DSF BPE Server
+
+```sh
+docker-compose up -d dic1-bpe && docker-compose logs -f dic1-fhir dic1-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
+
+```sh
+docker-compose up -d cos-bpe && docker-compose logs -f cos-fhir cos-bpe
+````
+
+
+
+*Start curl commands in console 5 from root-folder:* `mii-dsf-processes`
+
+Console 5: 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/Dic1FhirStore_Demo.xml \
+http://localhost:8080/fhir
+```
+
+Console 5: Start Data Send Process at DIC1 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://dic1/fhir/Task
+```
+
+Console 5: Check data transferred to COS
+
+```sh
+curl http://localhost:8082/fhir/DocumentReference
+```
+
+Console 5: Stop everything
+
+```sh
+docker-compose down -v
+```
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/README-Report-Process.md b/mii-dsf-processes-docker-test-setup/README-Report-Process.md
new file mode 100644
index 0000000..fba42bf
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/README-Report-Process.md
@@ -0,0 +1,100 @@
+# Report Process: Testing using Docker Setup
+
+Build the project from the root directory of this repository by executing the following command.
+
+```sh
+mvn clean package
+```
+
+Add entries to your hosts file
+
+```
+127.0.0.1 dic1
+127.0.0.1 hrp
+```
+
+*A total of four console windows are required. Start docker-compose commands for consoles 1 to 3 from
+sub-folder:* `mii-dsf-processes/mii-dsf-processes-docker-test-setup`
+
+Console 1: Start DIC1 HAPI FHIR Server
+
+```sh
+docker-compose up dic1-fhir-store-hapi
+```
+
+Access at http://localhost:8080/fhir/
+
+Console 2: Start DIC1 DSF FHIR Server and wait till started
+
+```sh
+docker-compose up -d dic1-fhir && docker-compose logs -f dic1-fhir
+```
+
+Console 2: Disconnect from log output (Ctrl-C) if Server started
+Console 2: Start DIC1 DSF BPE Server
+
+```sh
+docker-compose up -d dic1-bpe && docker-compose logs -f dic1-fhir dic1-bpe
+````
+
+Console 3: Start HRP DSF FHIR Server and wait till started
+
+```sh
+docker-compose up -d hrp-fhir && docker-compose logs -f hrp-fhir
+```
+
+Console 3: Disconnect from log output (Ctrl-C) if Server started
+Console 3: Start HRP DSF BPE Server
+
+```sh
+docker-compose up -d hrp-bpe && docker-compose logs -f hrp-fhir hrp-bpe
+````
+
+
+
+*Start curl commands in console 4 from root-folder:* `mii-dsf-processes`
+
+Console 4: Add the search Bundle to HRP DSF FHIR Server
+
+```sh
+curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \
+-d @mii-dsf-process-report/src/test/resources/fhir/Bundle/search-bundle.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://hrp/fhir/Bundle
+```
+
+Console 4: Start Report Send Process at DIC1 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* `ReportSendExampleStarter` *in*
+`mii-dsf-process-report/src/test/java/../bpe/start`
+
+```sh
+curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \
+-d @mii-dsf-process-report/src/test/resources/fhir/Task/report-send-start-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://dic1/fhir/Task
+```
+
+Console 4: Check data transferred to HRP
+
+```sh
+curl -H "Accept: application/xml+fhir" \
+--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://hrp/fhir/Bundle?identifier=http://highmed.org/sid/organization-identifier|Test_DIC1
+```
+
+Console 4: Stop everything
+
+```sh
+docker-compose down -v
+```
\ 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 0359884..b36f59b 100644
--- a/mii-dsf-processes-docker-test-setup/README.md
+++ b/mii-dsf-processes-docker-test-setup/README.md
@@ -1,100 +1,4 @@
# Testing using Docker Setup
-Build the project from the root directory of this repository by executing the following command.
-
-```sh
-mvn clean package
-```
-
-Add entries to your hosts file
-
-```
-127.0.0.1 dic
-127.0.0.1 cos
-```
-
-*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
-
-```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
-
-```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
-
-```sh
-docker-compose up -d cos-bpe && docker-compose logs -f cos-fhir cos-bpe
-````
-
-
-
-*Start curl commands in console 5 from root-folder:* `mii-dsf-processes`
-
-Console 5: 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 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 5: Check data transferred to COS
-
-```sh
-curl http://localhost:8081/fhir/DocumentReference
-```
-
-Console 5: Stop everything
-
-```sh
-docker-compose down -v
-```
\ No newline at end of file
+- To test the `Data Transfer Process`, follow the instructions in [README-Data-Transfer-Process.md](./README-Data-Transfer-Process.md)
+- To test the `Report Process`, follow the instructions in [README-Report-Process.md](./README-Report-Process.md)
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/db/init-db.sh b/mii-dsf-processes-docker-test-setup/db/init-db.sh
index 1861098..ebefd4f 100755
--- a/mii-dsf-processes-docker-test-setup/db/init-db.sh
+++ b/mii-dsf-processes-docker-test-setup/db/init-db.sh
@@ -2,12 +2,20 @@
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
- CREATE DATABASE dic_fhir;
- GRANT ALL PRIVILEGES ON DATABASE dic_fhir TO liquibase_user;
- CREATE DATABASE dic_bpe;
- GRANT ALL PRIVILEGES ON DATABASE dic_bpe TO liquibase_user;
+ CREATE DATABASE dic1_fhir;
+ GRANT ALL PRIVILEGES ON DATABASE dic1_fhir TO liquibase_user;
+ CREATE DATABASE dic1_bpe;
+ GRANT ALL PRIVILEGES ON DATABASE dic1_bpe TO liquibase_user;
+ CREATE DATABASE dic2_fhir;
+ GRANT ALL PRIVILEGES ON DATABASE dic2_fhir TO liquibase_user;
+ CREATE DATABASE dic2_bpe;
+ GRANT ALL PRIVILEGES ON DATABASE dic2_bpe TO liquibase_user;
CREATE DATABASE cos_fhir;
GRANT ALL PRIVILEGES ON DATABASE cos_fhir TO liquibase_user;
CREATE DATABASE cos_bpe;
GRANT ALL PRIVILEGES ON DATABASE cos_bpe TO liquibase_user;
+ CREATE DATABASE hrp_fhir;
+ GRANT ALL PRIVILEGES ON DATABASE hrp_fhir TO liquibase_user;
+ CREATE DATABASE hrp_bpe;
+ GRANT ALL PRIVILEGES ON DATABASE hrp_bpe TO liquibase_user;
EOSQL
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/dic/bpe/last_event/README.md b/mii-dsf-processes-docker-test-setup/dic1/bpe/last_event/README.md
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/dic/bpe/last_event/README.md
rename to mii-dsf-processes-docker-test-setup/dic1/bpe/last_event/README.md
diff --git a/mii-dsf-processes-docker-test-setup/dic/bpe/log/README.md b/mii-dsf-processes-docker-test-setup/dic1/bpe/log/README.md
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/dic/bpe/log/README.md
rename to mii-dsf-processes-docker-test-setup/dic1/bpe/log/README.md
diff --git a/mii-dsf-processes-docker-test-setup/dic/bpe/plugin/README.md b/mii-dsf-processes-docker-test-setup/dic1/bpe/plugin/README.md
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/dic/bpe/plugin/README.md
rename to mii-dsf-processes-docker-test-setup/dic1/bpe/plugin/README.md
diff --git a/mii-dsf-processes-docker-test-setup/dic/bpe/process/README.md b/mii-dsf-processes-docker-test-setup/dic1/bpe/process/README.md
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/dic/bpe/process/README.md
rename to mii-dsf-processes-docker-test-setup/dic1/bpe/process/README.md
diff --git a/mii-dsf-processes-docker-test-setup/dic/fhir/conf/README.md b/mii-dsf-processes-docker-test-setup/dic1/fhir/conf/README.md
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/dic/fhir/conf/README.md
rename to mii-dsf-processes-docker-test-setup/dic1/fhir/conf/README.md
diff --git a/mii-dsf-processes-docker-test-setup/dic/fhir/log/README.md b/mii-dsf-processes-docker-test-setup/dic1/fhir/log/README.md
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/dic/fhir/log/README.md
rename to mii-dsf-processes-docker-test-setup/dic1/fhir/log/README.md
diff --git a/mii-dsf-processes-docker-test-setup/dic/hapi/Dockerfile b/mii-dsf-processes-docker-test-setup/dic1/hapi/Dockerfile
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/dic/hapi/Dockerfile
rename to mii-dsf-processes-docker-test-setup/dic1/hapi/Dockerfile
diff --git a/mii-dsf-processes-docker-test-setup/dic/hapi/sample-logo.jpg b/mii-dsf-processes-docker-test-setup/dic1/hapi/sample-logo.jpg
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/dic/hapi/sample-logo.jpg
rename to mii-dsf-processes-docker-test-setup/dic1/hapi/sample-logo.jpg
diff --git a/mii-dsf-processes-docker-test-setup/dic2/bpe/last_event/README.md b/mii-dsf-processes-docker-test-setup/dic2/bpe/last_event/README.md
new file mode 100644
index 0000000..12fefbf
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/dic2/bpe/last_event/README.md
@@ -0,0 +1 @@
+empty directory for last-event time.file
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/dic2/bpe/log/README.md b/mii-dsf-processes-docker-test-setup/dic2/bpe/log/README.md
new file mode 100644
index 0000000..15ad4a6
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/dic2/bpe/log/README.md
@@ -0,0 +1 @@
+empty directory for log files
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/dic2/bpe/plugin/README.md b/mii-dsf-processes-docker-test-setup/dic2/bpe/plugin/README.md
new file mode 100644
index 0000000..be77010
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/dic2/bpe/plugin/README.md
@@ -0,0 +1 @@
+Empty folder for plugin jar files
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/dic2/bpe/process/README.md b/mii-dsf-processes-docker-test-setup/dic2/bpe/process/README.md
new file mode 100644
index 0000000..47c7890
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/dic2/bpe/process/README.md
@@ -0,0 +1 @@
+Empty folder for process jars
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/dic2/fhir/conf/README.md b/mii-dsf-processes-docker-test-setup/dic2/fhir/conf/README.md
new file mode 100644
index 0000000..db7195e
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/dic2/fhir/conf/README.md
@@ -0,0 +1 @@
+empty directory for conf files
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/dic2/fhir/log/README.md b/mii-dsf-processes-docker-test-setup/dic2/fhir/log/README.md
new file mode 100644
index 0000000..15ad4a6
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/dic2/fhir/log/README.md
@@ -0,0 +1 @@
+empty directory for log files
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/docker-compose.yml b/mii-dsf-processes-docker-test-setup/docker-compose.yml
index 8818749..00cb0b6 100644
--- a/mii-dsf-processes-docker-test-setup/docker-compose.yml
+++ b/mii-dsf-processes-docker-test-setup/docker-compose.yml
@@ -19,14 +19,20 @@ services:
target: /etc/nginx/nginx.conf
read_only: true
networks:
- dic-fhir-frontend:
+ dic1-fhir-frontend:
ipv4_address: 172.20.0.66
- cos-fhir-frontend:
+ dic2-fhir-frontend:
ipv4_address: 172.20.0.82
+ cos-fhir-frontend:
+ ipv4_address: 172.20.0.98
+ hrp-fhir-frontend:
+ ipv4_address: 172.20.0.114
internet:
aliases:
- - dic
+ - dic1
+ - dic2
- cos
+ - hrp
environment:
TZ: Europe/Berlin
@@ -45,10 +51,14 @@ services:
POSTGRES_USER: liquibase_user
POSTGRES_DB: postgres
networks:
- - dic-fhir-backend
+ - dic1-fhir-backend
+ - dic2-fhir-backend
- cos-fhir-backend
- - dic-bpe-backend
+ - hrp-fhir-backend
+ - dic1-bpe-backend
+ - dic2-bpe-backend
- cos-bpe-backend
+ - hrp-bpe-backend
secrets:
- db_liquibase.password
volumes:
@@ -61,127 +71,274 @@ services:
read_only: true
- dic-fhir:
- image: ghcr.io/highmed/fhir:0.5.5
+ dic1-fhir:
+ image: ghcr.io/highmed/fhir:0.7.0
restart: on-failure
+ healthcheck:
+ test: [ "CMD", "java", "-cp", "dsf_fhir.jar", "org.highmed.dsf.fhir.StatusClient" ]
+ interval: 10s
+ timeout: 15s
+ retries: 5
ports:
- 127.0.0.1:5000:5000
secrets:
- db_liquibase.password
- - db_dic_fhir_user.password
- - db_dic_fhir_user_permanent_delete.password
+ - db_dic1_fhir_user.password
+ - db_dic1_fhir_user_permanent_delete.password
- app_client_trust_certificates.pem
- - app_dic_client_certificate.pem
- - app_dic_client_certificate_private_key.pem
+ - app_dic1_client_certificate.pem
+ - app_dic1_client_certificate_private_key.pem
- app_client_certificate_private_key.pem.password
volumes:
- type: bind
- source: ./dic/fhir/conf/bundle.xml
+ source: ./dic1/fhir/conf/bundle.xml
target: /opt/fhir/conf/bundle.xml
- type: bind
- source: ./dic/fhir/log
+ source: ./dic1/fhir/log
target: /opt/fhir/log
environment:
TZ: Europe/Berlin
EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5000
ORG_HIGHMED_DSF_FHIR_DB_LIQUIBASE_PASSWORD_FILE: /run/secrets/db_liquibase.password
- ORG_HIGHMED_DSF_FHIR_DB_USER_PASSWORD_FILE: /run/secrets/db_dic_fhir_user.password
- ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_PASSWORD_FILE: /run/secrets/db_dic_fhir_user_permanent_delete.password
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PASSWORD_FILE: /run/secrets/db_dic1_fhir_user.password
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_PASSWORD_FILE: /run/secrets/db_dic1_fhir_user_permanent_delete.password
ORG_HIGHMED_DSF_FHIR_CLIENT_TRUST_CERTIFICATES: /run/secrets/app_client_trust_certificates.pem
- ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE: /run/secrets/app_dic_client_certificate.pem
- ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: /run/secrets/app_dic_client_certificate_private_key.pem
+ ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE: /run/secrets/app_dic1_client_certificate.pem
+ ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: /run/secrets/app_dic1_client_certificate_private_key.pem
ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: /run/secrets/app_client_certificate_private_key.pem.password
- ORG_HIGHMED_DSF_FHIR_DB_URL: jdbc:postgresql://db/dic_fhir
- ORG_HIGHMED_DSF_FHIR_DB_USER_GROUP: dic_fhir_users
- ORG_HIGHMED_DSF_FHIR_DB_USER_USERNAME: dic_fhir_server_user
- ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_GROUP: dic_fhir_permanent_delete_users
- ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_USERNAME: dic_fhir_server_permanent_delete_user
- ORG_HIGHMED_DSF_FHIR_SERVER_BASE_URL: https://dic/fhir
- ORG_HIGHMED_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_DIC
- ORG_HIGHMED_DSF_FHIR_SERVER_USER_THUMBPRINTS: ${DIC_USER_THUMBPRINTS}
- ORG_HIGHMED_DSF_FHIR_SERVER_USER_THUMBPRINTS_PERMANENT_DELETE: ${DIC_USER_THUMBPRINTS_PERMANENT_DELETE}
+ ORG_HIGHMED_DSF_FHIR_DB_URL: jdbc:postgresql://db/dic1_fhir
+ ORG_HIGHMED_DSF_FHIR_DB_USER_GROUP: dic1_fhir_users
+ ORG_HIGHMED_DSF_FHIR_DB_USER_USERNAME: dic1_fhir_server_user
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_GROUP: dic1_fhir_permanent_delete_users
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_USERNAME: dic1_fhir_server_permanent_delete_user
+ ORG_HIGHMED_DSF_FHIR_SERVER_BASE_URL: https://dic1/fhir
+ ORG_HIGHMED_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_DIC1
+ ORG_HIGHMED_DSF_FHIR_SERVER_USER_THUMBPRINTS: ${DIC1_USER_THUMBPRINTS}
+ ORG_HIGHMED_DSF_FHIR_SERVER_USER_THUMBPRINTS_PERMANENT_DELETE: ${DIC1_USER_THUMBPRINTS_PERMANENT_DELETE}
networks:
- dic-fhir-frontend:
+ dic1-fhir-frontend:
ipv4_address: 172.20.0.67
- dic-fhir-backend:
+ dic1-fhir-backend:
internet:
depends_on:
- db
- proxy
- dic-bpe:
- image: ghcr.io/highmed/bpe:0.5.5
+ dic1-bpe:
+ image: ghcr.io/highmed/bpe:0.7.0
restart: on-failure
+ healthcheck:
+ test: [ "CMD", "java", "-cp", "dsf_bpe.jar", "org.highmed.dsf.bpe.StatusClient" ]
+ interval: 10s
+ timeout: 15s
+ retries: 5
ports:
- - 127.0.0.1:5003:5003
+ - 127.0.0.1:5010:5010
secrets:
- db_liquibase.password
- - db_dic_bpe_user.password
- - db_dic_bpe_user_camunda.password
+ - db_dic1_bpe_user.password
+ - db_dic1_bpe_user_camunda.password
- app_client_trust_certificates.pem
- - app_dic_client_certificate.pem
- - app_dic_client_certificate_private_key.pem
+ - app_dic1_client_certificate.pem
+ - app_dic1_client_certificate_private_key.pem
- app_client_certificate_private_key.pem.password
- cos_public_key.pem
volumes:
- type: bind
- source: ./dic/bpe/plugin
+ source: ./dic1/bpe/plugin
target: /opt/bpe/plugin
read_only: true
- type: bind
- source: ./dic/bpe/process
+ source: ./dic1/bpe/process
target: /opt/bpe/process
read_only: true
- type: bind
- source: ./dic/bpe/log
+ source: ./dic1/bpe/log
target: /opt/bpe/log
- type: bind
- source: ./dic/bpe/last_event
+ source: ./dic1/bpe/last_event
target: /opt/bpe/last_event
environment:
TZ: Europe/Berlin
- EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5003
+ EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5010
ORG_HIGHMED_DSF_BPE_DB_LIQUIBASE_PASSWORD_FILE: /run/secrets/db_liquibase.password
- ORG_HIGHMED_DSF_BPE_DB_USER_PASSWORD_FILE: /run/secrets/db_dic_bpe_user.password
- ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_PASSWORD_FILE: /run/secrets/db_dic_bpe_user_camunda.password
+ ORG_HIGHMED_DSF_BPE_DB_USER_PASSWORD_FILE: /run/secrets/db_dic1_bpe_user.password
+ ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_PASSWORD_FILE: /run/secrets/db_dic1_bpe_user_camunda.password
ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_TRUST_CERTIFICATES: /run/secrets/app_client_trust_certificates.pem
- ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE: /run/secrets/app_dic_client_certificate.pem
- ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: /run/secrets/app_dic_client_certificate_private_key.pem
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE: /run/secrets/app_dic1_client_certificate.pem
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: /run/secrets/app_dic1_client_certificate_private_key.pem
ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: /run/secrets/app_client_certificate_private_key.pem.password
- ORG_HIGHMED_DSF_BPE_DB_URL: jdbc:postgresql://db/dic_bpe
- ORG_HIGHMED_DSF_BPE_DB_USER_GROUP: dic_bpe_users
- ORG_HIGHMED_DSF_BPE_DB_USER_USERNAME: dic_bpe_server_user
- ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_GROUP: dic_camunda_users
- ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_USERNAME: dic_camunda_server_user
- ORG_HIGHMED_DSF_BPE_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_DIC
- ORG_HIGHMED_DSF_BPE_FHIR_SERVER_BASE_URL: https://dic/fhir
- ORG_HIGHMED_DSF_BPE_PROCESS_EXCLUDED: medizininformatik-initiativede_dataReceive/0.1.0
- DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASE_URL: http://dic-fhir-store:8080/fhir
+ ORG_HIGHMED_DSF_BPE_DB_URL: jdbc:postgresql://db/dic1_bpe
+ ORG_HIGHMED_DSF_BPE_DB_USER_GROUP: dic1_bpe_users
+ ORG_HIGHMED_DSF_BPE_DB_USER_USERNAME: dic1_bpe_server_user
+ ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_GROUP: dic1_camunda_users
+ ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_USERNAME: dic1_camunda_server_user
+ ORG_HIGHMED_DSF_BPE_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_DIC1
+ ORG_HIGHMED_DSF_BPE_FHIR_SERVER_BASE_URL: https://dic1/fhir
+ ORG_HIGHMED_DSF_BPE_PROCESS_EXCLUDED: >-
+ medizininformatik-initiativede_dataReceive/${PROCESS_VERSION_DATA_TRANSFER},
+ medizininformatik-initiativede_kdsReportReceive/${PROCESS_VERSION_KDS_REPORT}
+ DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASE_URL: http://dic1-fhir-store:8080/fhir
+ DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_DATALOGGINGENABLED: true
networks:
- dic-bpe-frontend:
- dic-bpe-backend:
+ dic1-bpe-frontend:
+ dic1-bpe-backend:
internet:
depends_on:
- db
- - dic-fhir
- # - dic-fhir-store not defining a dependency here, dic-fhir-store* needs to be started manually
- dic-fhir-store-hapi:
- build: ./dic/hapi
+ - dic1-fhir
+ # - dic1-fhir-store not defining a dependency here, dic1-fhir-store* needs to be started manually
+ dic1-fhir-store-hapi:
+ build: ./dic1/hapi
restart: on-failure
ports:
- 127.0.0.1:8080:8080
environment:
TZ: Europe/Berlin
networks:
- dic-bpe-backend:
+ dic1-bpe-backend:
aliases:
- - dic-fhir-store
+ - dic1-fhir-store
- cos-fhir:
- image: ghcr.io/highmed/fhir:0.5.5
+ dic2-fhir:
+ image: ghcr.io/highmed/fhir:0.7.0
restart: on-failure
+ healthcheck:
+ test: [ "CMD", "java", "-cp", "dsf_fhir.jar", "org.highmed.dsf.fhir.StatusClient" ]
+ interval: 10s
+ timeout: 15s
+ retries: 5
ports:
- 127.0.0.1:5001:5001
+ secrets:
+ - db_liquibase.password
+ - db_dic2_fhir_user.password
+ - db_dic2_fhir_user_permanent_delete.password
+ - app_client_trust_certificates.pem
+ - app_dic2_client_certificate.pem
+ - app_dic2_client_certificate_private_key.pem
+ - app_client_certificate_private_key.pem.password
+ volumes:
+ - type: bind
+ source: ./dic2/fhir/conf/bundle.xml
+ target: /opt/fhir/conf/bundle.xml
+ - type: bind
+ source: ./dic2/fhir/log
+ target: /opt/fhir/log
+ environment:
+ TZ: Europe/Berlin
+ EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5001
+ ORG_HIGHMED_DSF_FHIR_DB_LIQUIBASE_PASSWORD_FILE: /run/secrets/db_liquibase.password
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PASSWORD_FILE: /run/secrets/db_dic2_fhir_user.password
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_PASSWORD_FILE: /run/secrets/db_dic2_fhir_user_permanent_delete.password
+ ORG_HIGHMED_DSF_FHIR_CLIENT_TRUST_CERTIFICATES: /run/secrets/app_client_trust_certificates.pem
+ ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE: /run/secrets/app_dic2_client_certificate.pem
+ ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: /run/secrets/app_dic2_client_certificate_private_key.pem
+ ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: /run/secrets/app_client_certificate_private_key.pem.password
+ ORG_HIGHMED_DSF_FHIR_DB_URL: jdbc:postgresql://db/dic2_fhir
+ ORG_HIGHMED_DSF_FHIR_DB_USER_GROUP: dic2_fhir_users
+ ORG_HIGHMED_DSF_FHIR_DB_USER_USERNAME: dic2_fhir_server_user
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_GROUP: dic2_fhir_permanent_delete_users
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_USERNAME: dic2_fhir_server_permanent_delete_user
+ ORG_HIGHMED_DSF_FHIR_SERVER_BASE_URL: https://dic2/fhir
+ ORG_HIGHMED_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_DIC2
+ ORG_HIGHMED_DSF_FHIR_SERVER_USER_THUMBPRINTS: ${DIC2_USER_THUMBPRINTS}
+ ORG_HIGHMED_DSF_FHIR_SERVER_USER_THUMBPRINTS_PERMANENT_DELETE: ${DIC2_USER_THUMBPRINTS_PERMANENT_DELETE}
+ networks:
+ dic2-fhir-frontend:
+ ipv4_address: 172.20.0.83
+ dic2-fhir-backend:
+ internet:
+ depends_on:
+ - db
+ - proxy
+ dic2-bpe:
+ image: ghcr.io/highmed/bpe:0.7.0
+ restart: on-failure
+ healthcheck:
+ test: [ "CMD", "java", "-cp", "dsf_bpe.jar", "org.highmed.dsf.bpe.StatusClient" ]
+ interval: 10s
+ timeout: 15s
+ retries: 5
+ ports:
+ - 127.0.0.1:5011:5011
+ secrets:
+ - db_liquibase.password
+ - db_dic2_bpe_user.password
+ - db_dic2_bpe_user_camunda.password
+ - app_client_trust_certificates.pem
+ - app_dic2_client_certificate.pem
+ - app_dic2_client_certificate_private_key.pem
+ - app_client_certificate_private_key.pem.password
+ - cos_public_key.pem
+ volumes:
+ - type: bind
+ source: ./dic2/bpe/plugin
+ target: /opt/bpe/plugin
+ read_only: true
+ - type: bind
+ source: ./dic2/bpe/process
+ target: /opt/bpe/process
+ read_only: true
+ - type: bind
+ source: ./dic2/bpe/log
+ target: /opt/bpe/log
+ - type: bind
+ source: ./dic2/bpe/last_event
+ target: /opt/bpe/last_event
+ environment:
+ TZ: Europe/Berlin
+ EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5011
+ ORG_HIGHMED_DSF_BPE_DB_LIQUIBASE_PASSWORD_FILE: /run/secrets/db_liquibase.password
+ ORG_HIGHMED_DSF_BPE_DB_USER_PASSWORD_FILE: /run/secrets/db_dic2_bpe_user.password
+ ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_PASSWORD_FILE: /run/secrets/db_dic2_bpe_user_camunda.password
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_TRUST_CERTIFICATES: /run/secrets/app_client_trust_certificates.pem
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE: /run/secrets/app_dic2_client_certificate.pem
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: /run/secrets/app_dic2_client_certificate_private_key.pem
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: /run/secrets/app_client_certificate_private_key.pem.password
+ ORG_HIGHMED_DSF_BPE_DB_URL: jdbc:postgresql://db/dic2_bpe
+ ORG_HIGHMED_DSF_BPE_DB_USER_GROUP: dic2_bpe_users
+ ORG_HIGHMED_DSF_BPE_DB_USER_USERNAME: dic2_bpe_server_user
+ ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_GROUP: dic2_camunda_users
+ ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_USERNAME: dic2_camunda_server_user
+ ORG_HIGHMED_DSF_BPE_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_DIC2
+ ORG_HIGHMED_DSF_BPE_FHIR_SERVER_BASE_URL: https://dic2/fhir
+ ORG_HIGHMED_DSF_BPE_PROCESS_EXCLUDED: >-
+ medizininformatik-initiativede_dataReceive/${PROCESS_VERSION_DATA_TRANSFER},
+ medizininformatik-initiativede_kdsReportReceive/${PROCESS_VERSION_KDS_REPORT}
+ DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASE_URL: http://dic2-fhir-store:8080/fhir
+ DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_TYPE: blaze
+ DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_DATALOGGINGENABLED: true
+ networks:
+ dic2-bpe-frontend:
+ dic2-bpe-backend:
+ internet:
+ depends_on:
+ - db
+ - dic2-fhir
+ # - dic2-fhir-store not defining a dependency here, dic2-fhir-store* needs to be started manually
+ dic2-fhir-store-blaze:
+ image: ghcr.io/num-codex/blaze
+ restart: on-failure
+ ports:
+ - 127.0.0.1:8080:8080
+ environment:
+ TZ: Europe/Berlin
+ networks:
+ dic2-bpe-backend:
+ aliases:
+ - dic2-fhir-store
+
+ cos-fhir:
+ image: ghcr.io/highmed/fhir:0.7.0
+ restart: on-failure
+ healthcheck:
+ test: [ "CMD", "java", "-cp", "dsf_fhir.jar", "org.highmed.dsf.fhir.StatusClient" ]
+ interval: 10s
+ timeout: 15s
+ retries: 5
+ ports:
+ - 127.0.0.1:5002:5002
secrets:
- db_liquibase.password
- db_cos_fhir_user.password
@@ -199,7 +356,7 @@ services:
target: /opt/fhir/log
environment:
TZ: Europe/Berlin
- EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5001
+ EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5002
ORG_HIGHMED_DSF_FHIR_DB_LIQUIBASE_PASSWORD_FILE: /run/secrets/db_liquibase.password
ORG_HIGHMED_DSF_FHIR_DB_USER_PASSWORD_FILE: /run/secrets/db_cos_fhir_user.password
ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_PASSWORD_FILE: /run/secrets/db_cos_fhir_user_permanent_delete.password
@@ -218,17 +375,22 @@ services:
ORG_HIGHMED_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_COS
networks:
cos-fhir-frontend:
- ipv4_address: 172.20.0.83
+ ipv4_address: 172.20.0.99
cos-fhir-backend:
internet:
depends_on:
- db
- proxy
cos-bpe:
- image: ghcr.io/highmed/bpe:0.5.5
+ image: ghcr.io/highmed/bpe:0.7.0
restart: on-failure
+ healthcheck:
+ test: [ "CMD", "java", "-cp", "dsf_bpe.jar", "org.highmed.dsf.bpe.StatusClient" ]
+ interval: 10s
+ timeout: 15s
+ retries: 5
ports:
- - 127.0.0.1:5004:5004
+ - 127.0.0.1:5012:5012
secrets:
- db_liquibase.password
- db_cos_bpe_user.password
@@ -256,7 +418,7 @@ services:
target: /opt/bpe/last_event
environment:
TZ: Europe/Berlin
- EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5004
+ EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5012
ORG_HIGHMED_DSF_BPE_DB_LIQUIBASE_PASSWORD_FILE: /run/secrets/db_liquibase.password
ORG_HIGHMED_DSF_BPE_DB_USER_PASSWORD_FILE: /run/secrets/db_cos_bpe_user.password
ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_PASSWORD_FILE: /run/secrets/db_cos_bpe_user_camunda.password
@@ -271,8 +433,9 @@ services:
ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_USERNAME: cos_camunda_server_user
ORG_HIGHMED_DSF_BPE_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_COS
ORG_HIGHMED_DSF_BPE_FHIR_SERVER_BASE_URL: https://cos/fhir
- ORG_HIGHMED_DSF_BPE_PROCESS_EXCLUDED: medizininformatik-initiativede_dataSend/0.1.0
+ ORG_HIGHMED_DSF_BPE_PROCESS_EXCLUDED: medizininformatik-initiativede_dataSend/${PROCESS_VERSION_DATA_TRANSFER}
DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASE_URL: http://cos-fhir-store:8080/fhir
+ DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_DATALOGGINGENABLED: true
DE_MEDIZININFORMATIK_INITIATIVE_COS_PRIVATE_KEY: /run/secrets/cos_private_key.pem
DE_MEDIZININFORMATIK_INITIATIVE_COS_PUBLIC_KEY: /run/secrets/cos_public_key.pem
networks:
@@ -287,7 +450,7 @@ services:
build: ./cos/hapi
restart: on-failure
ports:
- - 127.0.0.1:8081:8080
+ - 127.0.0.1:8082:8080
environment:
TZ: Europe/Berlin
networks:
@@ -296,6 +459,120 @@ services:
- cos-fhir-store
+ hrp-fhir:
+ image: ghcr.io/highmed/fhir:0.7.0
+ restart: on-failure
+ healthcheck:
+ test: [ "CMD", "java", "-cp", "dsf_fhir.jar", "org.highmed.dsf.fhir.StatusClient" ]
+ interval: 10s
+ timeout: 15s
+ retries: 5
+ ports:
+ - 127.0.0.1:5003:5003
+ secrets:
+ - db_liquibase.password
+ - db_hrp_fhir_user.password
+ - db_hrp_fhir_user_permanent_delete.password
+ - app_client_trust_certificates.pem
+ - app_hrp_client_certificate.pem
+ - app_hrp_client_certificate_private_key.pem
+ - app_client_certificate_private_key.pem.password
+ volumes:
+ - type: bind
+ source: ./hrp/fhir/conf/bundle.xml
+ target: /opt/fhir/conf/bundle.xml
+ - type: bind
+ source: ./hrp/fhir/log
+ target: /opt/fhir/log
+ environment:
+ TZ: Europe/Berlin
+ EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5003
+ ORG_HIGHMED_DSF_FHIR_DB_LIQUIBASE_PASSWORD_FILE: /run/secrets/db_liquibase.password
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PASSWORD_FILE: /run/secrets/db_hrp_fhir_user.password
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_PASSWORD_FILE: /run/secrets/db_hrp_fhir_user_permanent_delete.password
+ ORG_HIGHMED_DSF_FHIR_CLIENT_TRUST_CERTIFICATES: /run/secrets/app_client_trust_certificates.pem
+ ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE: /run/secrets/app_hrp_client_certificate.pem
+ ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: /run/secrets/app_hrp_client_certificate_private_key.pem
+ ORG_HIGHMED_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: /run/secrets/app_client_certificate_private_key.pem.password
+ ORG_HIGHMED_DSF_FHIR_DB_URL: jdbc:postgresql://db/hrp_fhir
+ ORG_HIGHMED_DSF_FHIR_DB_USER_GROUP: hrp_fhir_users
+ ORG_HIGHMED_DSF_FHIR_DB_USER_USERNAME: hrp_fhir_server_user
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_GROUP: hrp_fhir_permanent_delete_users
+ ORG_HIGHMED_DSF_FHIR_DB_USER_PERMANENT_DELETE_USERNAME: hrp_fhir_server_permanent_delete_user
+ ORG_HIGHMED_DSF_FHIR_SERVER_BASE_URL: https://hrp/fhir
+ ORG_HIGHMED_DSF_FHIR_SERVER_USER_THUMBPRINTS: ${HRP_USER_THUMBPRINTS}
+ ORG_HIGHMED_DSF_FHIR_SERVER_USER_THUMBPRINTS_PERMANENT_DELETE: ${HRP_USER_THUMBPRINTS_PERMANENT_DELETE}
+ ORG_HIGHMED_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_HRP
+ DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_DATALOGGINGENABLED: true
+ networks:
+ hrp-fhir-frontend:
+ ipv4_address: 172.20.0.115
+ hrp-fhir-backend:
+ internet:
+ depends_on:
+ - db
+ - proxy
+ hrp-bpe:
+ image: ghcr.io/highmed/bpe:0.7.0
+ restart: on-failure
+ healthcheck:
+ test: [ "CMD", "java", "-cp", "dsf_bpe.jar", "org.highmed.dsf.bpe.StatusClient" ]
+ interval: 10s
+ timeout: 15s
+ retries: 5
+ ports:
+ - 127.0.0.1:5013:5013
+ secrets:
+ - db_liquibase.password
+ - db_hrp_bpe_user.password
+ - db_hrp_bpe_user_camunda.password
+ - app_client_trust_certificates.pem
+ - app_hrp_client_certificate.pem
+ - app_hrp_client_certificate_private_key.pem
+ - app_client_certificate_private_key.pem.password
+ volumes:
+ - type: bind
+ source: ./hrp/bpe/plugin
+ target: /opt/bpe/plugin
+ read_only: true
+ - type: bind
+ source: ./hrp/bpe/process
+ target: /opt/bpe/process
+ read_only: true
+ - type: bind
+ source: ./hrp/bpe/log
+ target: /opt/bpe/log
+ - type: bind
+ source: ./hrp/bpe/last_event
+ target: /opt/bpe/last_event
+ environment:
+ TZ: Europe/Berlin
+ EXTRA_JVM_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5013
+ ORG_HIGHMED_DSF_BPE_DB_LIQUIBASE_PASSWORD_FILE: /run/secrets/db_liquibase.password
+ ORG_HIGHMED_DSF_BPE_DB_USER_PASSWORD_FILE: /run/secrets/db_hrp_bpe_user.password
+ ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_PASSWORD_FILE: /run/secrets/db_hrp_bpe_user_camunda.password
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_TRUST_CERTIFICATES: /run/secrets/app_client_trust_certificates.pem
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE: /run/secrets/app_hrp_client_certificate.pem
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: /run/secrets/app_hrp_client_certificate_private_key.pem
+ ORG_HIGHMED_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: /run/secrets/app_client_certificate_private_key.pem.password
+ ORG_HIGHMED_DSF_BPE_DB_URL: jdbc:postgresql://db/hrp_bpe
+ ORG_HIGHMED_DSF_BPE_DB_USER_GROUP: hrp_bpe_users
+ ORG_HIGHMED_DSF_BPE_DB_USER_USERNAME: hrp_bpe_server_user
+ ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_GROUP: hrp_camunda_users
+ ORG_HIGHMED_DSF_BPE_DB_USER_CAMUNDA_USERNAME: hrp_camunda_server_user
+ ORG_HIGHMED_DSF_BPE_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_HRP
+ ORG_HIGHMED_DSF_BPE_FHIR_SERVER_BASE_URL: https://hrp/fhir
+ ORG_HIGHMED_DSF_BPE_PROCESS_EXCLUDED: >-
+ medizininformatik-initiativede_kdsReportAutostart/${PROCESS_VERSION_KDS_REPORT},
+ medizininformatik-initiativede_kdsReportSend/${PROCESS_VERSION_KDS_REPORT}
+ networks:
+ hrp-bpe-frontend:
+ hrp-bpe-backend:
+ internet:
+ depends_on:
+ - db
+ - hrp-fhir
+
secrets:
proxy_certificate_and_int_cas.pem:
file: ./secrets/proxy_certificate_and_int_cas.pem
@@ -306,15 +583,24 @@ secrets:
db_liquibase.password:
file: ./secrets/db_liquibase.password
-
- db_dic_fhir_user.password:
- file: ./secrets/db_dic_fhir_user.password
- db_dic_fhir_user_permanent_delete.password:
- file: ./secrets/db_dic_fhir_user_permanent_delete.password
- db_dic_bpe_user.password:
- file: ./secrets/db_dic_bpe_user.password
- db_dic_bpe_user_camunda.password:
- file: ./secrets/db_dic_bpe_user_camunda.password
+
+ db_dic1_fhir_user.password:
+ file: ./secrets/db_dic1_fhir_user.password
+ db_dic1_fhir_user_permanent_delete.password:
+ file: ./secrets/db_dic1_fhir_user_permanent_delete.password
+ db_dic1_bpe_user.password:
+ file: ./secrets/db_dic1_bpe_user.password
+ db_dic1_bpe_user_camunda.password:
+ file: ./secrets/db_dic1_bpe_user_camunda.password
+
+ db_dic2_fhir_user.password:
+ file: ./secrets/db_dic2_fhir_user.password
+ db_dic2_fhir_user_permanent_delete.password:
+ file: ./secrets/db_dic2_fhir_user_permanent_delete.password
+ db_dic2_bpe_user.password:
+ file: ./secrets/db_dic2_bpe_user.password
+ db_dic2_bpe_user_camunda.password:
+ file: secrets/db_dic1_bpe_user_camunda.password
db_cos_fhir_user.password:
file: ./secrets/db_cos_fhir_user.password
@@ -325,21 +611,40 @@ secrets:
db_cos_bpe_user_camunda.password:
file: ./secrets/db_cos_bpe_user_camunda.password
+ db_hrp_fhir_user.password:
+ file: ./secrets/db_hrp_fhir_user.password
+ db_hrp_fhir_user_permanent_delete.password:
+ file: ./secrets/db_hrp_fhir_user_permanent_delete.password
+ db_hrp_bpe_user.password:
+ file: ./secrets/db_hrp_bpe_user.password
+ db_hrp_bpe_user_camunda.password:
+ file: ./secrets/db_hrp_bpe_user_camunda.password
+
app_client_trust_certificates.pem:
file: ./secrets/app_client_trust_certificates.pem
app_client_certificate_private_key.pem.password:
file: ./secrets/app_client_certificate_private_key.pem.password
- app_dic_client_certificate.pem:
- file: ./secrets/app_dic_client_certificate.pem
- app_dic_client_certificate_private_key.pem:
- file: ./secrets/app_dic_client_certificate_private_key.pem
+ app_dic1_client_certificate.pem:
+ file: ./secrets/app_dic1_client_certificate.pem
+ app_dic1_client_certificate_private_key.pem:
+ file: ./secrets/app_dic1_client_certificate_private_key.pem
+
+ app_dic2_client_certificate.pem:
+ file: ./secrets/app_dic2_client_certificate.pem
+ app_dic2_client_certificate_private_key.pem:
+ file: ./secrets/app_dic2_client_certificate_private_key.pem
app_cos_client_certificate.pem:
file: ./secrets/app_cos_client_certificate.pem
app_cos_client_certificate_private_key.pem:
file: ./secrets/app_cos_client_certificate_private_key.pem
+ app_hrp_client_certificate.pem:
+ file: ./secrets/app_hrp_client_certificate.pem
+ app_hrp_client_certificate_private_key.pem:
+ file: ./secrets/app_hrp_client_certificate_private_key.pem
+
cos_private_key.pem:
file: ./secrets/cos_private_key.pem
cos_public_key.pem:
@@ -347,24 +652,42 @@ secrets:
networks:
internet:
- dic-fhir-frontend:
+ dic1-fhir-frontend:
+ driver: bridge
+ ipam:
+ driver: default
+ config:
+ - subnet: 172.20.0.64/28
+ dic1-fhir-backend:
+ dic1-bpe-frontend:
+ dic1-bpe-backend:
+ dic2-fhir-frontend:
driver: bridge
ipam:
driver: default
config:
- - subnet: 172.20.0.64/28
- dic-fhir-backend:
- dic-bpe-frontend:
- dic-bpe-backend:
+ - subnet: 172.20.0.80/28
+ dic2-fhir-backend:
+ dic2-bpe-frontend:
+ dic2-bpe-backend:
cos-fhir-frontend:
driver: bridge
ipam:
driver: default
config:
- - subnet: 172.20.0.80/28
+ - subnet: 172.20.0.96/28
cos-fhir-backend:
cos-bpe-frontend:
cos-bpe-backend:
+ hrp-fhir-frontend:
+ driver: bridge
+ ipam:
+ driver: default
+ config:
+ - subnet: 172.20.0.112/28
+ hrp-fhir-backend:
+ hrp-bpe-frontend:
+ hrp-bpe-backend:
volumes:
diff --git a/mii-dsf-processes-docker-test-setup/hrp/bpe/last_event/README.md b/mii-dsf-processes-docker-test-setup/hrp/bpe/last_event/README.md
new file mode 100644
index 0000000..12fefbf
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/hrp/bpe/last_event/README.md
@@ -0,0 +1 @@
+empty directory for last-event time.file
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/hrp/bpe/log/README.md b/mii-dsf-processes-docker-test-setup/hrp/bpe/log/README.md
new file mode 100644
index 0000000..15ad4a6
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/hrp/bpe/log/README.md
@@ -0,0 +1 @@
+empty directory for log files
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/hrp/bpe/plugin/README.md b/mii-dsf-processes-docker-test-setup/hrp/bpe/plugin/README.md
new file mode 100644
index 0000000..be77010
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/hrp/bpe/plugin/README.md
@@ -0,0 +1 @@
+Empty folder for plugin jar files
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/hrp/bpe/process/README.md b/mii-dsf-processes-docker-test-setup/hrp/bpe/process/README.md
new file mode 100644
index 0000000..47c7890
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/hrp/bpe/process/README.md
@@ -0,0 +1 @@
+Empty folder for process jars
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/hrp/fhir/conf/README.md b/mii-dsf-processes-docker-test-setup/hrp/fhir/conf/README.md
new file mode 100644
index 0000000..db7195e
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/hrp/fhir/conf/README.md
@@ -0,0 +1 @@
+empty directory for conf files
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/hrp/fhir/log/README.md b/mii-dsf-processes-docker-test-setup/hrp/fhir/log/README.md
new file mode 100644
index 0000000..15ad4a6
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/hrp/fhir/log/README.md
@@ -0,0 +1 @@
+empty directory for log files
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/proxy/conf.d/cos.conf b/mii-dsf-processes-docker-test-setup/proxy/conf.d/cos.conf
index ceeecd5..90ffbe3 100644
--- a/mii-dsf-processes-docker-test-setup/proxy/conf.d/cos.conf
+++ b/mii-dsf-processes-docker-test-setup/proxy/conf.d/cos.conf
@@ -6,7 +6,7 @@ server {
location / {
proxy_set_header X-ClientCert $ssl_client_escaped_cert;
- proxy_pass http://172.20.0.83:8080;
+ proxy_pass http://172.20.0.99:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
diff --git a/mii-dsf-processes-docker-test-setup/proxy/conf.d/dic.conf b/mii-dsf-processes-docker-test-setup/proxy/conf.d/dic1.conf
similarity index 94%
rename from mii-dsf-processes-docker-test-setup/proxy/conf.d/dic.conf
rename to mii-dsf-processes-docker-test-setup/proxy/conf.d/dic1.conf
index 64c2ed3..d438e03 100644
--- a/mii-dsf-processes-docker-test-setup/proxy/conf.d/dic.conf
+++ b/mii-dsf-processes-docker-test-setup/proxy/conf.d/dic1.conf
@@ -1,7 +1,7 @@
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
- server_name dic;
+ server_name dic1;
location / {
proxy_set_header X-ClientCert $ssl_client_escaped_cert;
diff --git a/mii-dsf-processes-docker-test-setup/proxy/conf.d/dic2.conf b/mii-dsf-processes-docker-test-setup/proxy/conf.d/dic2.conf
new file mode 100644
index 0000000..b9a19ad
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/proxy/conf.d/dic2.conf
@@ -0,0 +1,16 @@
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ server_name dic2;
+
+ location / {
+ proxy_set_header X-ClientCert $ssl_client_escaped_cert;
+
+ proxy_pass http://172.20.0.83:8080;
+
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_read_timeout 43200s;
+ }
+}
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/proxy/conf.d/hrp.conf b/mii-dsf-processes-docker-test-setup/proxy/conf.d/hrp.conf
new file mode 100644
index 0000000..fbddd19
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/proxy/conf.d/hrp.conf
@@ -0,0 +1,16 @@
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ server_name hrp;
+
+ location / {
+ proxy_set_header X-ClientCert $ssl_client_escaped_cert;
+
+ proxy_pass http://172.20.0.115:8080;
+
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_read_timeout 43200s;
+ }
+}
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_dic_bpe_user.password b/mii-dsf-processes-docker-test-setup/secrets/db_dic1_bpe_user.password
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/secrets/db_dic_bpe_user.password
rename to mii-dsf-processes-docker-test-setup/secrets/db_dic1_bpe_user.password
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_dic_bpe_user_camunda.password b/mii-dsf-processes-docker-test-setup/secrets/db_dic1_bpe_user_camunda.password
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/secrets/db_dic_bpe_user_camunda.password
rename to mii-dsf-processes-docker-test-setup/secrets/db_dic1_bpe_user_camunda.password
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_dic_fhir_user.password b/mii-dsf-processes-docker-test-setup/secrets/db_dic1_fhir_user.password
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/secrets/db_dic_fhir_user.password
rename to mii-dsf-processes-docker-test-setup/secrets/db_dic1_fhir_user.password
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_dic_fhir_user_permanent_delete.password b/mii-dsf-processes-docker-test-setup/secrets/db_dic1_fhir_user_permanent_delete.password
similarity index 100%
rename from mii-dsf-processes-docker-test-setup/secrets/db_dic_fhir_user_permanent_delete.password
rename to mii-dsf-processes-docker-test-setup/secrets/db_dic1_fhir_user_permanent_delete.password
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_dic2_bpe_user.password b/mii-dsf-processes-docker-test-setup/secrets/db_dic2_bpe_user.password
new file mode 100644
index 0000000..27c25fd
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/secrets/db_dic2_bpe_user.password
@@ -0,0 +1 @@
+MKzGrbrHbre8iKGBXPQr6saYdmwkdKR6
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_dic2_bpe_user_camunda.password b/mii-dsf-processes-docker-test-setup/secrets/db_dic2_bpe_user_camunda.password
new file mode 100644
index 0000000..65c0175
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/secrets/db_dic2_bpe_user_camunda.password
@@ -0,0 +1 @@
+hZFk7WMDtN7EDPDiwqNJtFwfgq7TqHyg
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_dic2_fhir_user.password b/mii-dsf-processes-docker-test-setup/secrets/db_dic2_fhir_user.password
new file mode 100644
index 0000000..e9bb727
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/secrets/db_dic2_fhir_user.password
@@ -0,0 +1 @@
+VZio9gJkoAotGBzvf6zm4QivtNaqedQG
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_dic2_fhir_user_permanent_delete.password b/mii-dsf-processes-docker-test-setup/secrets/db_dic2_fhir_user_permanent_delete.password
new file mode 100644
index 0000000..c2e113e
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/secrets/db_dic2_fhir_user_permanent_delete.password
@@ -0,0 +1 @@
+rmk2ZHjVv6qBaBcauD4PF24EQ7MLwDaa
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_hrp_bpe_user.password b/mii-dsf-processes-docker-test-setup/secrets/db_hrp_bpe_user.password
new file mode 100644
index 0000000..d449a36
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/secrets/db_hrp_bpe_user.password
@@ -0,0 +1 @@
+4qgXyViUTutWfRjjzrXcLoZtr8Ryqc8g
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_hrp_bpe_user_camunda.password b/mii-dsf-processes-docker-test-setup/secrets/db_hrp_bpe_user_camunda.password
new file mode 100644
index 0000000..14a13a7
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/secrets/db_hrp_bpe_user_camunda.password
@@ -0,0 +1 @@
+dEr6ffCoQvRy3vnjNqYgV4UCMV2LKJYT
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_hrp_fhir_user.password b/mii-dsf-processes-docker-test-setup/secrets/db_hrp_fhir_user.password
new file mode 100644
index 0000000..59cec8b
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/secrets/db_hrp_fhir_user.password
@@ -0,0 +1 @@
+wce88MwBXt6rEUaB2htCV66LjAdXNcee
\ No newline at end of file
diff --git a/mii-dsf-processes-docker-test-setup/secrets/db_hrp_fhir_user_permanent_delete.password b/mii-dsf-processes-docker-test-setup/secrets/db_hrp_fhir_user_permanent_delete.password
new file mode 100644
index 0000000..d8d2286
--- /dev/null
+++ b/mii-dsf-processes-docker-test-setup/secrets/db_hrp_fhir_user_permanent_delete.password
@@ -0,0 +1 @@
+yQvLzfNRN7zHvgPVXawMssTB8gMtfAK2
\ No newline at end of file
diff --git a/mii-dsf-processes-documentation-generator/pom.xml b/mii-dsf-processes-documentation-generator/pom.xml
deleted file mode 100644
index 277409c..0000000
--- a/mii-dsf-processes-documentation-generator/pom.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
- 4.0.0
-
- mii-dsf-processes-documentation-generator
-
-
- de.medizininformatik-initiative
- mii-dsf-processes
- 0.1.0
-
-
-
- ${project.basedir}/..
-
-
-
-
- org.highmed.dsf
- dsf-bpe-process-base
-
-
- de.hs-heilbronn.mi
- log4j2-utils
-
-
- org.reflections
- reflections
-
-
-
\ No newline at end of file
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
deleted file mode 100644
index d4e8b78..0000000
--- a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package de.medizininformatik_initiative.processes.documentation.generator;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface Documentation
-{
- /**
- * @return true
if this property is required for processes that are listed in
- * {@link Documentation#processNames}
- */
- boolean required() default false;
-
- /**
- * @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;
-
- /**
- * @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
deleted file mode 100644
index 06dc7f0..0000000
--- a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/DocumentationGenerator.java
+++ /dev/null
@@ -1,196 +0,0 @@
-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.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;
-import org.reflections.util.ConfigurationBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-
-public class DocumentationGenerator
-{
- private static final Logger logger = LoggerFactory.getLogger(DocumentationGenerator.class);
-
- public static void main(String[] args)
- {
- new DocumentationGenerator().execute(args);
- }
-
- public void execute(String[] args)
- {
- Arrays.asList(args).forEach(this::generateDocumentation);
- }
-
- private void generateDocumentation(String workingPackage)
- {
- 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);
-
- writeFields(fields, pluginProcessNames, filename, workingPackage);
- }
-
- private Reflections createReflections(String workingPackage)
- {
- ConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
- .setUrls(ClasspathHelper.forPackage(workingPackage))
- .setScanners(Scanners.FieldsAnnotated, Scanners.SubTypes);
- return new Reflections(configurationBuilder);
- }
-
- 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(Documentation.class));
- Collections.reverse(fields);
- return fields;
- }
-
- private void writeFields(List fields, List pluginProcessNames, String filename,
- String workingPackage)
- {
- try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename)))
- {
- fields.stream().map(field -> createDocumentation(field, pluginProcessNames))
- .forEach(d -> write(writer, filename, d));
- }
- catch (Exception exception)
- {
- logger.warn("Could not generate documentation for package {}, reason is '{}'", workingPackage,
- exception.getMessage());
- }
- }
-
- 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.join(", ", documentationProcessNames);
- }
-
- private void write(BufferedWriter writer, String filename, String string)
- {
- try
- {
- writer.append(string);
- }
- catch (IOException e)
- {
- 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
deleted file mode 100644
index e8e6da7..0000000
--- a/mii-dsf-processes-documentation-generator/src/main/resources/log4j2.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/mii-dsf-processes-kds-client/pom.xml b/mii-dsf-processes-kds-client/pom.xml
new file mode 100644
index 0000000..f51853f
--- /dev/null
+++ b/mii-dsf-processes-kds-client/pom.xml
@@ -0,0 +1,76 @@
+
+
+ 4.0.0
+
+ mii-dsf-processes-kds-client
+
+
+ mii-dsf-processes
+ de.medizininformatik-initiative
+ 0.2.0-SNAPSHOT
+
+
+
+ ${project.basedir}/..
+
+
+
+
+ org.highmed.dsf
+ dsf-bpe-process-base
+ provided
+
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-client
+ provided
+
+
+ ca.uhn.hapi.fhir
+ hapi-fhir-structures-r4
+ provided
+
+
+
+ org.highmed.dsf
+ dsf-tools-documentation-generator
+ provided
+
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+
+ exec
+
+ prepare-package
+
+
+
+ java
+
+ -classpath
+
+
+ org.highmed.dsf.tools.generator.DocumentationGenerator
+
+
+ de.medizininformatik_initiative.processes.kds.client
+
+
+ true
+ true
+ compile
+ ${project.basedir}
+
+
+
+
+
\ 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/ApacheRestfulClientFactoryWithTlsConfig.java b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/ApacheRestfulClientFactoryWithTlsConfig.java
similarity index 98%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/ApacheRestfulClientFactoryWithTlsConfig.java
rename to mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/ApacheRestfulClientFactoryWithTlsConfig.java
index f824f0d..1968582 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/ApacheRestfulClientFactoryWithTlsConfig.java
+++ b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/ApacheRestfulClientFactoryWithTlsConfig.java
@@ -1,4 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client;
+package de.medizininformatik_initiative.processes.kds.client;
import java.security.KeyManagementException;
import java.security.KeyStore;
diff --git a/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClient.java b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClient.java
new file mode 100644
index 0000000..771dd82
--- /dev/null
+++ b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClient.java
@@ -0,0 +1,28 @@
+package de.medizininformatik_initiative.processes.kds.client;
+
+import org.hl7.fhir.r4.model.Binary;
+import org.hl7.fhir.r4.model.Bundle;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
+
+public interface KdsClient
+{
+ String getLocalIdentifierValue();
+
+ FhirContext getFhirContext();
+
+ String getFhirBaseUrl();
+
+ IGenericClient getGenericFhirClient();
+
+ void testConnection();
+
+ Bundle searchDocumentReferences(String system, String code);
+
+ Binary readBinary(String url);
+
+ Bundle executeTransactionBundle(Bundle toExecute);
+
+ Bundle executeBatchBundle(Bundle toExecute);
+}
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-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClientFactory.java
similarity index 86%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java
rename to mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClientFactory.java
index e3b96b6..85928ae 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java
+++ b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClientFactory.java
@@ -1,4 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client;
+package de.medizininformatik_initiative.processes.kds.client;
import java.io.IOException;
import java.nio.file.Path;
@@ -14,11 +14,9 @@
import org.bouncycastle.pkcs.PKCSException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-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.client.fhir.KdsFhirClient;
+import de.medizininformatik_initiative.processes.kds.client.logging.DataLogger;
import de.rwh.utils.crypto.CertificateHelper;
import de.rwh.utils.crypto.io.CertificateReader;
import de.rwh.utils.crypto.io.PemIo;
@@ -48,17 +46,17 @@ public class KdsClientFactory
private final boolean hapiClientVerbose;
private final FhirContext fhirContext;
- private final Class kdsFhirClientClass;
private final String localIdentifierValue;
+ private final DataLogger dataLogger;
+
public KdsClientFactory(Path trustStorePath, Path certificatePath, Path privateKeyPath, char[] privateKeyPassword,
int connectTimeout, int socketTimeout, int connectionRequestTimeout, String kdsServerBase,
String kdsServerBasicAuthUsername, String kdsServerBasicAuthPassword, String kdsServerBearerToken,
String proxyUrl, String proxyUsername, String proxyPassword, boolean hapiClientVerbose,
- FhirContext fhirContext, Class kdsFhirClientClass, String localIdentifierValue)
+ FhirContext fhirContext, String localIdentifierValue, DataLogger dataLogger)
{
- super();
this.trustStorePath = trustStorePath;
this.certificatePath = certificatePath;
this.privateKeyPath = privateKeyPath;
@@ -79,13 +77,13 @@ public KdsClientFactory(Path trustStorePath, Path certificatePath, Path privateK
this.hapiClientVerbose = hapiClientVerbose;
this.fhirContext = fhirContext;
- this.kdsFhirClientClass = kdsFhirClientClass;
this.localIdentifierValue = localIdentifierValue;
+
+ this.dataLogger = dataLogger;
}
- @EventListener({ ContextRefreshedEvent.class })
- public void onContextRefreshedEvent(ContextRefreshedEvent event)
+ public void testConnection()
{
try
{
@@ -108,9 +106,9 @@ public void onContextRefreshedEvent(ContextRefreshedEvent event)
public KdsClient getKdsClient()
{
if (configured())
- return createKdsClient();
+ return createKdsClientImpl();
else
- return new KdsClientStub(fhirContext, localIdentifierValue);
+ return createKdsClientStub();
}
private boolean configured()
@@ -118,7 +116,12 @@ private boolean configured()
return kdsServerBase != null && !kdsServerBase.isBlank();
}
- protected KdsClient createKdsClient()
+ protected KdsClient createKdsClientStub()
+ {
+ return new KdsClientStub(fhirContext, localIdentifierValue);
+ }
+
+ protected KdsClient createKdsClientImpl()
{
KeyStore trustStore = null;
char[] keyStorePassword = null;
@@ -140,7 +143,7 @@ protected KdsClient createKdsClient()
return new KdsClientImpl(trustStore, keyStore, keyStorePassword, connectTimeout, socketTimeout,
connectionRequestTimeout, kdsServerBasicAuthUsername, kdsServerBasicAuthPassword, kdsServerBearerToken,
kdsServerBase, proxyUrl, proxyUsername, proxyPassword, hapiClientVerbose, fhirContext,
- kdsFhirClientClass, localIdentifierValue);
+ localIdentifierValue, dataLogger);
}
private KeyStore readTrustStore(Path trustPath)
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientImpl.java b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClientImpl.java
similarity index 71%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientImpl.java
rename to mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClientImpl.java
index aca1c3f..fd7d6ab 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientImpl.java
+++ b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClientImpl.java
@@ -1,12 +1,16 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client;
+package de.medizininformatik_initiative.processes.kds.client;
+
+import static ca.uhn.fhir.rest.api.Constants.HEADER_PREFER;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyStore;
+import org.hl7.fhir.r4.model.Binary;
+import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.CapabilityStatement;
+import org.hl7.fhir.r4.model.DocumentReference;
+import org.hl7.fhir.r4.model.IdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -17,7 +21,8 @@
import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;
import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
-import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir.KdsFhirClient;
+import de.medizininformatik_initiative.processes.kds.client.logging.DataLogger;
+import de.medizininformatik_initiative.processes.kds.client.logging.HapiClientLogger;
public class KdsClientImpl implements KdsClient
{
@@ -34,15 +39,16 @@ public class KdsClientImpl implements KdsClient
private final boolean hapiClientVerbose;
private final FhirContext fhirContext;
- private final Class kdsFhirClientClass;
private final String localIdentifierValue;
+ private final DataLogger dataLogger;
+
public KdsClientImpl(KeyStore trustStore, KeyStore keyStore, char[] keyStorePassword, int connectTimeout,
int socketTimeout, int connectionRequestTimeout, String kdsServerBasicAuthUsername,
String kdsServerBasicAuthPassword, String kdsServerBearerToken, String kdsServerBase, String proxyUrl,
String proxyUsername, String proxyPassword, boolean hapiClientVerbose, FhirContext fhirContext,
- Class kdsFhirClientClass, String localIdentifierValue)
+ String localIdentifierValue, DataLogger dataLogger)
{
clientFactory = createClientFactory(trustStore, keyStore, keyStorePassword, connectTimeout, socketTimeout,
connectionRequestTimeout);
@@ -58,9 +64,10 @@ public KdsClientImpl(KeyStore trustStore, KeyStore keyStore, char[] keyStorePass
this.hapiClientVerbose = hapiClientVerbose;
this.fhirContext = fhirContext;
- this.kdsFhirClientClass = kdsFhirClientClass;
this.localIdentifierValue = localIdentifierValue;
+
+ this.dataLogger = dataLogger;
}
private void configureProxy(IRestfulClientFactory clientFactory, String proxyUrl, String proxyUsername,
@@ -124,36 +131,21 @@ private void configureLoggingInterceptor(IGenericClient client)
}
@Override
- public void testConnection()
+ public String getLocalIdentifierValue()
{
- CapabilityStatement statement = getGenericFhirClient().capabilities().ofType(CapabilityStatement.class)
- .execute();
-
- logger.info("Connection test OK {} - {}", statement.getSoftware().getName(),
- statement.getSoftware().getVersion());
+ return localIdentifierValue;
}
@Override
- public KdsFhirClient getFhirClient()
+ public FhirContext getFhirContext()
{
- try
- {
- Constructor constructor = kdsFhirClientClass.getConstructor(KdsClient.class);
-
- return constructor.newInstance(this);
- }
- catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
- | IllegalArgumentException | InvocationTargetException e)
- {
- logger.warn("Error while creating KDS FHIR client: {}", e.getMessage());
- throw new RuntimeException(e);
- }
+ return fhirContext;
}
@Override
- public FhirContext getFhirContext()
+ public String getFhirBaseUrl()
{
- return fhirContext;
+ return kdsServerBase;
}
@Override
@@ -169,14 +161,62 @@ public IGenericClient getGenericFhirClient()
}
@Override
- public String getLocalIdentifierValue()
+ public void testConnection()
{
- return localIdentifierValue;
+ CapabilityStatement statement = getGenericFhirClient().capabilities().ofType(CapabilityStatement.class)
+ .execute();
+
+ logger.info("Connection test OK {} - {}", statement.getSoftware().getName(),
+ statement.getSoftware().getVersion());
}
@Override
- public String getFhirBaseUrl()
+ public Bundle searchDocumentReferences(String system, String code)
{
- return kdsServerBase;
+ Bundle toReturn = getGenericFhirClient().search().forResource(DocumentReference.class)
+ .where(DocumentReference.IDENTIFIER.exactly().systemAndIdentifier(system, code))
+ .returnBundle(Bundle.class).execute();
+
+ dataLogger.logResource("DocumentReference Search-Response Bundle based on system|code=" + system + "|" + code,
+ toReturn);
+
+ return toReturn;
+ }
+
+ @Override
+ public Binary readBinary(String url)
+ {
+ Binary toReturn = getGenericFhirClient().read().resource(Binary.class).withId(new IdType(url).getIdPart())
+ .execute();
+
+ dataLogger.logResource("Read Binary from url=" + url, toReturn);
+
+ return toReturn;
+ }
+
+ @Override
+ public Bundle executeTransactionBundle(Bundle toExecute)
+ {
+ dataLogger.logResource("Executing Transaction Bundle", toExecute);
+
+ Bundle toReturn = getGenericFhirClient().transaction().withBundle(toExecute)
+ .withAdditionalHeader(HEADER_PREFER, "handling=strict").execute();
+
+ dataLogger.logResource("Transaction Bundle Response", toReturn);
+
+ return toReturn;
+ }
+
+ @Override
+ public Bundle executeBatchBundle(Bundle toExecute)
+ {
+ dataLogger.logResource("Executing Batch Bundle", toExecute);
+
+ Bundle toReturn = getGenericFhirClient().transaction().withBundle(toExecute)
+ .withAdditionalHeader(HEADER_PREFER, "handling=strict").execute();
+
+ dataLogger.logResource("Batch Bundle Response", toReturn);
+
+ return toReturn;
}
}
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-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClientStub.java
similarity index 94%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientStub.java
rename to mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClientStub.java
index da77ddf..2f2f1e3 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-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/KdsClientStub.java
@@ -1,4 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir;
+package de.medizininformatik_initiative.processes.kds.client;
import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER;
import static org.hl7.fhir.r4.model.Bundle.BundleType.TRANSACTIONRESPONSE;
@@ -14,16 +14,55 @@
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;
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
-public final class KdsFhirClientStub implements KdsFhirClient
+public class KdsClientStub implements KdsClient
{
- private final KdsClient kdsClient;
+ private static final Logger logger = LoggerFactory.getLogger(KdsClientStub.class);
- public KdsFhirClientStub(KdsClient kdsClient)
+ private final FhirContext fhirContext;
+ private final String localIdentifierValue;
+ private final String kdsServerBase;
+
+ KdsClientStub(FhirContext fhirContext, String localIdentifierValue)
+ {
+ this.fhirContext = fhirContext;
+ this.localIdentifierValue = localIdentifierValue;
+ this.kdsServerBase = "http://foo.bar/fhir";
+ }
+
+ @Override
+ public String getLocalIdentifierValue()
+ {
+ return localIdentifierValue;
+ }
+
+ @Override
+ public FhirContext getFhirContext()
{
- this.kdsClient = kdsClient;
+ return fhirContext;
+ }
+
+ @Override
+ public String getFhirBaseUrl()
+ {
+ return kdsServerBase;
+ }
+
+ @Override
+ public IGenericClient getGenericFhirClient()
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public void testConnection()
+ {
+ logger.warn("Stub implementation, no connection test performed");
}
@Override
@@ -32,7 +71,7 @@ public Bundle searchDocumentReferences(String system, String code)
DocumentReference documentReference = new DocumentReference().setStatus(CURRENT).setDocStatus(FINAL);
documentReference.getMasterIdentifier().setSystem(system).setValue(code);
documentReference.addAuthor().setType(ResourceType.Organization.name()).getIdentifier()
- .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue(kdsClient.getLocalIdentifierValue());
+ .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER).setValue(getLocalIdentifierValue());
documentReference.setDate(new Date());
documentReference.addContent().getAttachment().setContentType("text/csv")
.setUrl(ResourceType.Binary.name() + "/" + UUID.randomUUID().toString());
@@ -54,7 +93,7 @@ public Binary readBinary(String url)
}
@Override
- public Bundle storeBundle(Bundle toStore)
+ public Bundle executeTransactionBundle(Bundle toExecute)
{
Bundle bundle = new Bundle().setType(TRANSACTIONRESPONSE);
bundle.setId(UUID.randomUUID().toString());
@@ -328,4 +367,13 @@ private byte[] getData()
+ "Y3VzIiwiYWlyIiwiZGlubmVyIiwicmFkaW8iLCJwb3B1bGF0aW9uIiwiY291cnNlIiwic2xpcHBlZCIsIm1ldGFsI"
+ "iwic3RpbGwiLCJwb2xpY2VtYW4iLCJzdGVlcCI=").getBytes(StandardCharsets.UTF_8);
}
-}
\ No newline at end of file
+
+ @Override
+ public Bundle executeBatchBundle(Bundle toExecute)
+ {
+ Bundle bundle = new Bundle();
+ bundle.setType(Bundle.BundleType.BATCHRESPONSE);
+
+ return bundle;
+ }
+}
diff --git a/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/logging/DataLogger.java b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/logging/DataLogger.java
new file mode 100644
index 0000000..8490e3a
--- /dev/null
+++ b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/logging/DataLogger.java
@@ -0,0 +1,32 @@
+package de.medizininformatik_initiative.processes.kds.client.logging;
+
+import org.hl7.fhir.r4.model.Resource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ca.uhn.fhir.context.FhirContext;
+
+public class DataLogger
+{
+ private static final Logger logger = LoggerFactory.getLogger(DataLogger.class);
+
+ private final boolean enabled;
+ private final FhirContext fhirContext;
+
+ public DataLogger(boolean enabled, FhirContext fhirContext)
+ {
+ this.enabled = enabled;
+ this.fhirContext = fhirContext;
+ }
+
+ public void logResource(String logMessage, Resource resource)
+ {
+ if (enabled)
+ logger.debug("{}: {}", logMessage, asString(resource));
+ }
+
+ private String asString(Resource resource)
+ {
+ return fhirContext.newJsonParser().encodeResourceToString(resource);
+ }
+}
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/HapiClientLogger.java b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/logging/HapiClientLogger.java
similarity index 98%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/HapiClientLogger.java
rename to mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/logging/HapiClientLogger.java
index b993730..7251a98 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/HapiClientLogger.java
+++ b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/logging/HapiClientLogger.java
@@ -1,4 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client;
+package de.medizininformatik_initiative.processes.kds.client.logging;
import org.slf4j.Logger;
import org.slf4j.Marker;
diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/OutcomeLogger.java b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/logging/OutcomeLogger.java
similarity index 93%
rename from mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/OutcomeLogger.java
rename to mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/logging/OutcomeLogger.java
index aa80b4e..5c9a57e 100644
--- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/OutcomeLogger.java
+++ b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/logging/OutcomeLogger.java
@@ -1,4 +1,4 @@
-package de.medizininformatik_initiative.processes.projectathon.data_transfer.client;
+package de.medizininformatik_initiative.processes.kds.client.logging;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
diff --git a/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/spring/config/PropertiesConfig.java b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/spring/config/PropertiesConfig.java
new file mode 100644
index 0000000..cd897c4
--- /dev/null
+++ b/mii-dsf-processes-kds-client/src/main/java/de/medizininformatik_initiative/processes/kds/client/spring/config/PropertiesConfig.java
@@ -0,0 +1,123 @@
+package de.medizininformatik_initiative.processes.kds.client.spring.config;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.highmed.dsf.tools.generator.ProcessDocumentation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import ca.uhn.fhir.context.FhirContext;
+import de.medizininformatik_initiative.processes.kds.client.KdsClientFactory;
+import de.medizininformatik_initiative.processes.kds.client.logging.DataLogger;
+
+@Configuration
+public class PropertiesConfig
+{
+ @Autowired
+ private FhirContext fhirContext;
+
+ @ProcessDocumentation(required = true, description = "The base address of the KDS FHIR server to read/store FHIR resources", example = "http://foo.bar/fhir")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.base.url:#{null}}")
+ private String fhirStoreBaseUrl;
+
+ @ProcessDocumentation(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;
+
+ @ProcessDocumentation(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;
+
+ @ProcessDocumentation(description = "Private key corresponding to the KDS FHIR server client-certificate as PEM encoded file. Use *${env_variable}_PASSWORD* or *${env_variable}_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;
+
+ @ProcessDocumentation(description = "Password to decrypt the KDS FHIR server client-certificate encrypted private key", recommendation = "Use docker secret file to configure by using *${env_variable}_FILE*", example = "/run/secrets/kds_server_private_key.pem.password")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.private.key.password:#{null}}")
+ private char[] fhirStorePrivateKeyPassword;
+
+ @ProcessDocumentation(description = "Basic authentication username, set if the server containing the FHIR KDS data requests authentication using basic auth")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.basicauth.username:#{null}}")
+ private String fhirStoreUsername;
+
+ @ProcessDocumentation(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 *${env_variable}_FILE*", example = "/run/secrets/kds_server_basicauth.password")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.basicauth.password:#{null}}")
+ private String fhirStorePassword;
+
+ @ProcessDocumentation(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")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.bearer.token:#{null}}")
+ private String fhirStoreBearerToken;
+
+ @ProcessDocumentation(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")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.timeout.connect:10000}")
+ private int fhirStoreConnectTimeout;
+
+ @ProcessDocumentation(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")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.timeout.connection.request:10000}")
+ private int fhirStoreConnectionRequestTimeout;
+
+ @ProcessDocumentation(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")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.timeout.socket:10000}")
+ private int fhirStoreSocketTimeout;
+
+ @ProcessDocumentation(description = "The KDS client will log additional debug output", recommendation = "Change default value only if exceptions occur")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.client.verbose:false}")
+ private boolean fhirStoreHapiClientVerbose;
+
+ @ProcessDocumentation(description = "Proxy location, set if the server containing the FHIR KDS data can only be reached through a proxy", example = "http://proxy.foo:8080")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.proxy.url:#{null}}")
+ private String fhirStoreProxyUrl;
+
+ @ProcessDocumentation(description = "Proxy username, set if the server containing the FHIR KDS data can only be reached through a proxy which requests authentication")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.proxy.username:#{null}}")
+ private String fhirStoreProxyUsername;
+
+ @ProcessDocumentation(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 *${env_variable}_FILE*")
+ @Value("${de.medizininformatik.initiative.kds.fhir.server.proxy.password:#{null}}")
+ private String fhirStoreProxyPassword;
+
+ @ProcessDocumentation(description = "To enable debug logging of FHIR resources set to `true`")
+ @Value("${de.medizininformatik.initiative.kds.fhir.dataLoggingEnabled:false}")
+ private boolean fhirDataLoggingEnabled;
+
+ @Value("${org.highmed.dsf.bpe.fhir.server.organization.identifier.value}")
+ private String localIdentifierValue;
+
+ @Bean
+ public KdsClientFactory kdsClientFactory()
+ {
+ Path trustStorePath = checkExists(fhirStoreTrustStore);
+ Path certificatePath = checkExists(fhirStoreCertificate);
+ Path privateKeyPath = checkExists(fhirStorePrivateKey);
+
+ return new KdsClientFactory(trustStorePath, certificatePath, privateKeyPath, fhirStorePrivateKeyPassword,
+ fhirStoreConnectTimeout, fhirStoreSocketTimeout, fhirStoreConnectionRequestTimeout, fhirStoreBaseUrl,
+ fhirStoreUsername, fhirStorePassword, fhirStoreBearerToken, fhirStoreProxyUrl, fhirStoreProxyUsername,
+ fhirStoreProxyPassword, fhirStoreHapiClientVerbose, fhirContext, localIdentifierValue, dataLogger());
+ }
+
+ private Path checkExists(String file)
+ {
+ if (file == null)
+ return null;
+ else
+ {
+ Path path = Paths.get(file);
+
+ if (!Files.isReadable(path))
+ throw new RuntimeException(path.toString() + " not readable");
+
+ return path;
+ }
+ }
+
+ @Bean
+ public DataLogger dataLogger()
+ {
+ return new DataLogger(fhirDataLoggingEnabled, fhirContext);
+ }
+}
diff --git a/mii-dsf-processes-test-data-generator/pom.xml b/mii-dsf-processes-test-data-generator/pom.xml
index 423e51d..9779b89 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
+ 0.2.0-SNAPSHOT
@@ -16,6 +16,14 @@
+
+ de.medizininformatik-initiative
+ mii-dsf-process-projectathon-data-transfer
+
+
+ de.medizininformatik-initiative
+ mii-dsf-process-kds-report
+
de.hs-heilbronn.mi
log4j2-utils
diff --git a/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/BundleGenerator.java b/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/BundleGenerator.java
index 2f9e9f8..ffc9600 100644
--- a/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/BundleGenerator.java
+++ b/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/BundleGenerator.java
@@ -81,34 +81,53 @@ public void createDockerTestBundles(
private void createDockerTestBundle(
Map clientCertificateFilesByCommonName)
{
- Path medic3BundleTemplateFile = Paths.get("src/main/resources/bundle-templates/bundle.xml");
+ Path bundleTemplateFile = Paths.get("src/main/resources/bundle-templates/bundle.xml");
- bundle = readAndCleanBundle(medic3BundleTemplateFile);
+ bundle = readAndCleanBundle(bundleTemplateFile);
- Organization organizationCos = (Organization) bundle.getEntry().get(0).getResource();
+ Organization organizationHrp = (Organization) bundle.getEntry().get(0).getResource();
+ Extension organizationHrpThumbprintExtension = organizationHrp
+ .getExtensionByUrl("http://highmed.org/fhir/StructureDefinition/extension-certificate-thumbprint");
+ organizationHrpThumbprintExtension.setValue(new StringType(
+ clientCertificateFilesByCommonName.get("hrp-client").getCertificateSha512ThumbprintHex()));
+
+ Organization organizationCos = (Organization) bundle.getEntry().get(1).getResource();
Extension organizationCosThumbprintExtension = organizationCos
.getExtensionByUrl("http://highmed.org/fhir/StructureDefinition/extension-certificate-thumbprint");
organizationCosThumbprintExtension.setValue(new StringType(
clientCertificateFilesByCommonName.get("cos-client").getCertificateSha512ThumbprintHex()));
- Organization organizationDic = (Organization) bundle.getEntry().get(1).getResource();
- Extension organizationMedic1thumbprintExtension = organizationDic
+ Organization organizationDic1 = (Organization) bundle.getEntry().get(2).getResource();
+ Extension organizationDic1thumbprintExtension = organizationDic1
.getExtensionByUrl("http://highmed.org/fhir/StructureDefinition/extension-certificate-thumbprint");
- organizationMedic1thumbprintExtension.setValue(new StringType(
- clientCertificateFilesByCommonName.get("dic-client").getCertificateSha512ThumbprintHex()));
+ organizationDic1thumbprintExtension.setValue(new StringType(
+ clientCertificateFilesByCommonName.get("dic1-client").getCertificateSha512ThumbprintHex()));
+
+ Organization organizationDic2 = (Organization) bundle.getEntry().get(3).getResource();
+ Extension organizationDic2thumbprintExtension = organizationDic2
+ .getExtensionByUrl("http://highmed.org/fhir/StructureDefinition/extension-certificate-thumbprint");
+ organizationDic2thumbprintExtension.setValue(new StringType(
+ clientCertificateFilesByCommonName.get("dic2-client").getCertificateSha512ThumbprintHex()));
writeBundle(Paths.get("bundle/bundle.xml"), bundle);
}
public void copyDockerTestBundles()
{
- Path dicBundleFile = Paths.get("../mii-dsf-processes-docker-test-setup/dic/fhir/conf/bundle.xml");
- logger.info("Copying fhir bundle to {}", dicBundleFile);
- writeBundle(dicBundleFile, bundle);
+ Path hrpBundleFile = Paths.get("../mii-dsf-processes-docker-test-setup/hrp/fhir/conf/bundle.xml");
+ logger.info("Copying fhir bundle to {}", hrpBundleFile);
+ writeBundle(hrpBundleFile, bundle);
Path cosBundleFile = Paths.get("../mii-dsf-processes-docker-test-setup/cos/fhir/conf/bundle.xml");
logger.info("Copying fhir bundle to {}", cosBundleFile);
writeBundle(cosBundleFile, bundle);
+ Path dic1BundleFile = Paths.get("../mii-dsf-processes-docker-test-setup/dic1/fhir/conf/bundle.xml");
+ logger.info("Copying fhir bundle to {}", dic1BundleFile);
+ writeBundle(dic1BundleFile, bundle);
+
+ Path dic2BundleFile = Paths.get("../mii-dsf-processes-docker-test-setup/dic2/fhir/conf/bundle.xml");
+ logger.info("Copying fhir bundle to {}", dic2BundleFile);
+ writeBundle(dic2BundleFile, bundle);
}
}
diff --git a/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/CertificateGenerator.java b/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/CertificateGenerator.java
index b0cfc32..d00aafc 100644
--- a/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/CertificateGenerator.java
+++ b/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/CertificateGenerator.java
@@ -55,8 +55,9 @@ public class CertificateGenerator
private static final char[] CERT_PASSWORD = "password".toCharArray();
- private static final String[] SERVER_COMMON_NAMES = { "localhost", "cos", "dic" };
- private static final String[] CLIENT_COMMON_NAMES = { "cos-client", "dic-client", "Webbrowser Test User" };
+ private static final String[] SERVER_COMMON_NAMES = { "localhost", "hrp", "cos", "dic1", "dic2" };
+ private static final String[] CLIENT_COMMON_NAMES = { "hrp-client", "cos-client", "dic1-client", "dic2-client",
+ "Webbrowser Test User" };
private static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();
diff --git a/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/EnvGenerator.java b/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/EnvGenerator.java
index cf90027..fa3469a 100644
--- a/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/EnvGenerator.java
+++ b/mii-dsf-processes-test-data-generator/src/main/java/de/medizininformatik_initiative/processes/test/data/generator/EnvGenerator.java
@@ -15,6 +15,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import de.medizininformatik_initiative.process.kds.report.KdsReportProcessPluginDefinition;
+import de.medizininformatik_initiative.process.projectathon.data_transfer.DataTransferProcessPluginDefinition;
import de.medizininformatik_initiative.processes.test.data.generator.CertificateGenerator.CertificateFiles;
public class EnvGenerator
@@ -23,6 +25,8 @@ public class EnvGenerator
private static final String USER_THUMBPRINTS = "USER_THUMBPRINTS";
private static final String USER_THUMBPRINTS_PERMANENTDELETE = "USER_THUMBPRINTS_PERMANENT_DELETE";
+ private static final String PROCESS_VERSION_DATA_TRANSFER = "PROCESS_VERSION_DATA_TRANSFER";
+ private static final String PROCESS_VERSION_REPORT = "PROCESS_VERSION_KDS_REPORT";
private static final class EnvEntry
{
@@ -43,23 +47,41 @@ private static final class EnvEntry
public void generateAndWriteDockerTestFhirEnvFiles(Map clientCertificateFilesByCommonName)
{
- Stream dicUserThumbprints = filterAndMapToThumbprint(clientCertificateFilesByCommonName, "dic-client",
+ Stream dic1UserThumbprints = filterAndMapToThumbprint(clientCertificateFilesByCommonName, "dic1-client",
"Webbrowser Test User");
- Stream dicUserThumbprintsPermanentDelete = filterAndMapToThumbprint(clientCertificateFilesByCommonName,
- "dic-client", "Webbrowser Test User");
+ Stream dic1UserThumbprintsPermanentDelete = filterAndMapToThumbprint(clientCertificateFilesByCommonName,
+ "dic1-client", "Webbrowser Test User");
+
+ Stream dic2UserThumbprints = filterAndMapToThumbprint(clientCertificateFilesByCommonName, "dic2-client",
+ "Webbrowser Test User");
+ Stream dic2UserThumbprintsPermanentDelete = filterAndMapToThumbprint(clientCertificateFilesByCommonName,
+ "dic2-client", "Webbrowser Test User");
Stream cosUserThumbprints = filterAndMapToThumbprint(clientCertificateFilesByCommonName, "cos-client",
"Webbrowser Test User");
Stream cosUserThumbprintsPermanentDelete = filterAndMapToThumbprint(clientCertificateFilesByCommonName,
"cos-client", "Webbrowser Test User");
+ Stream hrpUserThumbprints = filterAndMapToThumbprint(clientCertificateFilesByCommonName, "hrp-client",
+ "Webbrowser Test User");
+ Stream hrpUserThumbprintsPermanentDelete = filterAndMapToThumbprint(clientCertificateFilesByCommonName,
+ "hrp-client", "Webbrowser Test User");
+
List entries = List.of(
- new EnvEntry("DIC_" + USER_THUMBPRINTS, dicUserThumbprints, "DIC_" + USER_THUMBPRINTS_PERMANENTDELETE,
- dicUserThumbprintsPermanentDelete),
+ new EnvEntry("DIC1_" + USER_THUMBPRINTS, dic1UserThumbprints,
+ "DIC1_" + USER_THUMBPRINTS_PERMANENTDELETE, dic1UserThumbprintsPermanentDelete),
+ new EnvEntry("DIC2_" + USER_THUMBPRINTS, dic2UserThumbprints,
+ "DIC2_" + USER_THUMBPRINTS_PERMANENTDELETE, dic2UserThumbprintsPermanentDelete),
new EnvEntry("COS_" + USER_THUMBPRINTS, cosUserThumbprints, "COS_" + USER_THUMBPRINTS_PERMANENTDELETE,
- cosUserThumbprintsPermanentDelete));
+ cosUserThumbprintsPermanentDelete),
+ new EnvEntry("HRP_" + USER_THUMBPRINTS, hrpUserThumbprints, "HRP_" + USER_THUMBPRINTS_PERMANENTDELETE,
+ hrpUserThumbprintsPermanentDelete));
+
+ Map additionalEntries = Map.of(PROCESS_VERSION_DATA_TRANSFER,
+ DataTransferProcessPluginDefinition.VERSION, PROCESS_VERSION_REPORT,
+ KdsReportProcessPluginDefinition.VERSION);
- writeEnvFile(Paths.get("../mii-dsf-processes-docker-test-setup/.env"), entries);
+ writeEnvFile(Paths.get("../mii-dsf-processes-docker-test-setup/.env"), entries, additionalEntries);
}
private Stream filterAndMapToThumbprint(Map clientCertificateFilesByCommonName,
@@ -71,7 +93,7 @@ private Stream filterAndMapToThumbprint(Map cl
.map(CertificateFiles::getCertificateSha512ThumbprintHex);
}
- private void writeEnvFile(Path target, List extends EnvEntry> entries)
+ private void writeEnvFile(Path target, List extends EnvEntry> entries, Map additionalEntries)
{
StringBuilder builder = new StringBuilder();
@@ -91,6 +113,17 @@ private void writeEnvFile(Path target, List extends EnvEntry> entries)
builder.append("\n\n");
}
+ if (!additionalEntries.isEmpty())
+ builder.append('\n');
+
+ for (var entry : additionalEntries.entrySet())
+ {
+ builder.append('\n');
+ builder.append(entry.getKey());
+ builder.append('=');
+ builder.append(entry.getValue());
+ }
+
try
{
logger.info("Writing .env file to {}", target.toString());
diff --git a/mii-dsf-processes-test-data-generator/src/main/resources/bundle-templates/bundle.xml b/mii-dsf-processes-test-data-generator/src/main/resources/bundle-templates/bundle.xml
index e7028cf..51af12b 100644
--- a/mii-dsf-processes-test-data-generator/src/main/resources/bundle-templates/bundle.xml
+++ b/mii-dsf-processes-test-data-generator/src/main/resources/bundle-templates/bundle.xml
@@ -1,5 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -21,7 +58,7 @@
-
+
@@ -53,16 +90,16 @@
-
+
-
+
-
+
@@ -71,7 +108,85 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -128,14 +243,14 @@
-
+
-
+
@@ -148,12 +263,53 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -180,6 +336,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -202,7 +395,7 @@
-
+
@@ -239,7 +432,7 @@
-
+
@@ -251,7 +444,44 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 36ad01b..c531936 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,13 +6,14 @@
de.medizininformatik-initiative
mii-dsf-processes
- 0.1.0
+ 0.2.0-SNAPSHOT
pom
mii-dsf-process-projectathon-data-transfer
- mii-dsf-processes-documentation-generator
+ mii-dsf-process-kds-report
mii-dsf-processes-test-data-generator
+ mii-dsf-processes-kds-client
@@ -22,9 +23,7 @@
${project.basedir}
5.1.0
- 0.5.5
- 2.3.0
- mii-dsf-processes
+ 0.7.0
Business processes for the Medical Informatics Initiative as plugins for the HiGHmed Data
@@ -65,11 +64,26 @@
+
+ de.medizininformatik-initiative
+ mii-dsf-process-projectathon-data-transfer
+ ${project.version}
+
+
+ de.medizininformatik-initiative
+ mii-dsf-process-kds-report
+ ${project.version}
+
de.medizininformatik-initiative
mii-dsf-processes-documentation-generator
${project.version}
+
+ de.medizininformatik-initiative
+ mii-dsf-processes-kds-client
+ ${project.version}
+
@@ -92,6 +106,11 @@
dsf-fhir-server
${dsf.version}
+
+ org.highmed.dsf
+ dsf-tools-documentation-generator
+ ${dsf.version}
+
@@ -109,12 +128,12 @@
de.hs-heilbronn.mi
log4j2-utils
- 0.12.0
+ 0.13.0
de.hs-heilbronn.mi
crypto-utils
- 3.2.0
+ 3.3.0
@@ -126,19 +145,19 @@
- org.apache.tika
- tika-core
- ${apache.tika.version}
+ org.springframework
+ spring-web
+ 5.3.20
- org.reflections
- reflections
- 0.10.2
+ org.apache.tika
+ tika-core
+ 2.4.0
com.fasterxml.jackson.core
jackson-annotations
- 2.12.0
+ 2.13.2
@@ -147,6 +166,11 @@
junit
4.13.2
+
+ org.mockito
+ mockito-core
+ 3.5.13
+
org.highmed.dsf
dsf-bpe-process-base
@@ -163,7 +187,7 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.8.1
+ 3.10.1
${compileTarget}
@@ -172,12 +196,12 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.0.0-M5
+ 3.0.0-M6
org.apache.maven.plugins
maven-jar-plugin
- 3.2.0
+ 3.2.2
@@ -191,8 +215,11 @@
-
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.4
+
org.apache.maven.plugins
maven-assembly-plugin
@@ -201,17 +228,17 @@
org.apache.maven.plugins
maven-dependency-plugin
- 3.2.0
+ 3.3.0
org.apache.maven.plugins
maven-clean-plugin
- 3.1.0
+ 3.2.0
net.revelc.code.formatter
formatter-maven-plugin
- 2.17.1
+ 2.18.0
net.revelc.code