Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dry-run functionality #53

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>de.medizininformatik-initiative</groupId>
<artifactId>mii-process-report</artifactId>
<version>1.1.3.0-SNAPSHOT</version>
<version>1.2.0.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down Expand Up @@ -45,7 +45,7 @@
<dependency>
<groupId>de.medizininformatik-initiative</groupId>
<artifactId>mii-processes-common</artifactId>
<version>1.0.3.0</version>
<version>1.1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ public interface ConstantsReport
String BPMN_EXECUTION_VARIABLE_REPORT_SEARCH_BUNDLE_RESPONSE_REFERENCE = "reportSearchBundleResponseReference";
String BPMN_EXECUTION_VARIABLE_REPORT_RECEIVE_ERROR = "reportReceiveError";
String BPMN_EXECUTION_VARIABLE_REPORT_RECEIVE_ERROR_MESSAGE = "reportReceiveErrorMessage";
String BPMN_EXECUTION_VARIABLE_IS_DRY_RUN = "isDryRun";

String CODESYSTEM_REPORT = "http://medizininformatik-initiative.de/fhir/CodeSystem/report";

String CODESYSTEM_REPORT_VALUE_SEARCH_BUNDLE = "search-bundle-v";
String CODESYSTEM_REPORT_VALUE_SEARCH_BUNDLE_RESPONSE_REFERENCE = "search-bundle-response-reference";
String CODESYSTEM_REPORT_VALUE_REPORT_STATUS = "report-status";
String CODESYSTEM_REPORT_VALUE_TIMER_INTERVAL = "timer-interval";
String CODESYSTEM_REPORT_VALUE_FIRST_EXECUTION = "first-execution";
String CODESYSTEM_REPORT_VALUE_HRP_IDENTIFIER = "hrp-identifier";
String CODESYSTEM_REPORT_VALUE_DRY_RUN = "dry-run";

String CODESYSTEM_REPORT_STATUS = "http://medizininformatik-initiative.de/fhir/CodeSystem/report-status";
String CODESYSTEM_REPORT_STATUS_VALUE_NOT_ALLOWED = "not-allowed";
Expand All @@ -59,8 +59,11 @@ public interface ConstantsReport
String CODESYSTEM_REPORT_STATUS_VALUE_RECEIPT_ERROR = "receipt-error";
String CODESYSTEM_REPORT_STATUS_VALUE_RECEIVE_OK = "receive-ok";
String CODESYSTEM_REPORT_STATUS_VALUE_RECEIVE_ERROR = "receive-error";
String CODESYSTEM_REPORT_STATUS_VALUE_DRY_RUN = "dry-run";

String NAMINGSYSTEM_CDS_REPORT_IDENTIFIER = "http://medizininformatik-initiative.de/sid/cds-report-identifier";
String NAMINGSYSTEM_SEARCH_BUNDLE_IDENTIFIER = "http://medizininformatik-initiative.de/sid/search-bundle-identifier";
String NAMINGSYSTEM_SEARCH_BUNDLE_IDENTIFIER_VALUE_PREFIX = "search-bundle-v";

String PROFILE_REPORT_SEARCH_BUNDLE_RESPONSE = "http://medizininformatik-initiative.de/fhir/Bundle/search-bundle-response-report";
String EXTENSION_REPORT_STATUS_ERROR_URL = "http://medizininformatik-initiative.de/fhir/StructureDefinition/extension-report-status-error";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

public class ReportProcessPluginDefinition implements ProcessPluginDefinition
{
public static final String VERSION = "1.1.3.0";
public static final String VERSION = "1.2.0.0";
public static final LocalDate RELEASE_DATE = LocalDate.of(2024, 11, 10);

@Override
Expand Down Expand Up @@ -55,6 +55,7 @@ public Map<String, List<String>> getFhirResourcesByProcessId()
var eReportStatusError = "fhir/StructureDefinition/extension-report-status-error.xml";

var nReportIdent = "fhir/NamingSystem/cds-report-identifier.xml";
var nSearchBundleIdent = "fhir/NamingSystem/search-bundle-identifier.xml";

var sAutostartStart = "fhir/StructureDefinition/task-report-autostart-start.xml";
var sAutostartStop = "fhir/StructureDefinition/task-report-autostart-stop.xml";
Expand All @@ -75,10 +76,10 @@ public Map<String, List<String>> getFhirResourcesByProcessId()
return Map.of(ConstantsReport.PROCESS_NAME_FULL_REPORT_AUTOSTART,
List.of(aAutostart, cReport, sAutostartStart, sAutostartStop, tAutostartStart, tAutostartStop, vReport),
ConstantsReport.PROCESS_NAME_FULL_REPORT_RECEIVE,
List.of(aReceive, cReport, cReportStatus, eReportStatusError, nReportIdent, sSearchBundle,
sSearchBundleResponse, sSend, vReport, vReportStatusReceive),
List.of(aReceive, cReport, cReportStatus, eReportStatusError, nReportIdent, nSearchBundleIdent,
sSearchBundle, sSearchBundleResponse, sSend, vReport, vReportStatusReceive),
ConstantsReport.PROCESS_NAME_FULL_REPORT_SEND,
List.of(aSend, cReport, cReportStatus, eReportStatusError, nReportIdent, sReceive, sSearchBundle,
sSearchBundleResponse, sSendStart, tSendStart, vReport, vReportStatusSend));
List.of(aSend, cReport, cReportStatus, eReportStatusError, nReportIdent, nSearchBundleIdent, sReceive,
sSearchBundle, sSearchBundleResponse, sSendStart, tSendStart, vReport, vReportStatusSend));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,17 @@ public class CreateReport extends AbstractServiceDelegate implements Initializin

private final String resourceVersion;
private final FhirClientFactory fhirClientFactory;
private final boolean fhirAsyncRequestsEnabled;
private final DataLogger dataLogger;

public CreateReport(ProcessPluginApi api, String resourceVersion, FhirClientFactory fhirClientFactory,
DataLogger dataLogger)
boolean fhirAsyncRequestsEnabled, DataLogger dataLogger)
{
super(api);

this.resourceVersion = resourceVersion;
this.fhirClientFactory = fhirClientFactory;
this.fhirAsyncRequestsEnabled = fhirAsyncRequestsEnabled;
this.dataLogger = dataLogger;
}

Expand All @@ -67,12 +69,13 @@ protected void doExecute(DelegateExecution execution, Variables variables)
Task task = variables.getStartTask();
Bundle searchBundle = variables.getResource(ConstantsReport.BPMN_EXECUTION_VARIABLE_REPORT_SEARCH_BUNDLE);
Target target = variables.getTarget();
boolean isDryRun = variables.getBoolean(ConstantsReport.BPMN_EXECUTION_VARIABLE_IS_DRY_RUN);

try
{
Bundle responseBundle = executeSearchBundle(searchBundle, target.getOrganizationIdentifierValue());

Bundle reportBundle = transformToReportBundle(searchBundle, responseBundle, target);
Bundle reportBundle = transformToReportBundle(searchBundle, responseBundle, target, isDryRun);
dataLogger.logResource("Report Bundle", reportBundle);

checkReportBundle(searchBundle, reportBundle, target.getOrganizationIdentifierValue());
Expand All @@ -94,8 +97,8 @@ protected void doExecute(DelegateExecution execution, Variables variables)
private Bundle executeSearchBundle(Bundle searchBundle, String hrpIdentifier)
{
logger.info(
"Executing search Bundle from HRP '{}' against FHIR store with base url '{}' - this could take a while...",
hrpIdentifier, fhirClientFactory.getFhirClient().getFhirBaseUrl());
"Executing search Bundle from HRP '{}' against FHIR store with base URL '{}' - this could take a while...",
hrpIdentifier, fhirClientFactory.getFhirBaseUrl());

Bundle responseBundle = new Bundle();
responseBundle.setType(Bundle.BundleType.BATCHRESPONSE);
Expand All @@ -115,9 +118,10 @@ private Bundle.BundleEntryComponent executeRequest(String url)

try
{
logger.debug("Executing report search request '{}'", url);
logger.debug("Executing report search request '{}' with {}", url,
fhirAsyncRequestsEnabled ? "asnyc request pattern" : "normal request pattern");
Resource result = doExecuteRequest(url);

Resource result = fhirClientFactory.getFhirClient().search(url);
entry.setResource(result);
entry.setResponse(new Bundle.BundleEntryResponseComponent().setStatus(RESPONSE_OK));
}
Expand All @@ -137,7 +141,15 @@ private Bundle.BundleEntryComponent executeRequest(String url)
return entry;
}

private Bundle transformToReportBundle(Bundle searchBundle, Bundle responseBundle, Target target)
private Resource doExecuteRequest(String url)
{
if (fhirAsyncRequestsEnabled)
return fhirClientFactory.getAsyncFhirClient().search(url);
else
return fhirClientFactory.getStandardFhirClient().search(url);
}

private Bundle transformToReportBundle(Bundle searchBundle, Bundle responseBundle, Target target, boolean isDryRun)
{
Bundle report = new Bundle();
report.setMeta(responseBundle.getMeta());
Expand All @@ -150,7 +162,8 @@ private Bundle transformToReportBundle(Bundle searchBundle, Bundle responseBundl
.orElseThrow(() -> new RuntimeException("LocalOrganizationIdentifierValue empty"))));

api.getReadAccessHelper().addLocal(report);
api.getReadAccessHelper().addOrganization(report, target.getOrganizationIdentifierValue());
if (!isDryRun)
api.getReadAccessHelper().addOrganization(report, target.getOrganizationIdentifierValue());

for (int i = 0; i < searchBundle.getEntry().size(); i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ protected void doExecute(DelegateExecution execution, Variables variables)
{
Task task = variables.getStartTask();
Target target = variables.getTarget();
String searchBundleIdentifier = ConstantsReport.CODESYSTEM_REPORT + "|"
+ ConstantsReport.CODESYSTEM_REPORT_VALUE_SEARCH_BUNDLE + processVersion;
String searchBundleIdentifier = ConstantsReport.NAMINGSYSTEM_SEARCH_BUNDLE_IDENTIFIER + "|"
+ ConstantsReport.NAMINGSYSTEM_SEARCH_BUNDLE_IDENTIFIER_VALUE_PREFIX + processVersion;

logger.info("Downloading search Bundle '{}' from HRP '{}' for Task with id '{}'", searchBundleIdentifier,
target.getOrganizationIdentifierValue(), task.getId());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package de.medizininformatik_initiative.process.report.service;

import java.util.Objects;

import org.camunda.bpm.engine.delegate.DelegateExecution;
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.report.ConstantsReport;
import de.medizininformatik_initiative.process.report.util.ReportStatusGenerator;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
import dev.dsf.bpe.v1.variables.Variables;

public class LogDryRun extends AbstractServiceDelegate implements InitializingBean
{
private static final Logger logger = LoggerFactory.getLogger(LogDryRun.class);

private final ReportStatusGenerator statusGenerator;

public LogDryRun(ProcessPluginApi api, ReportStatusGenerator statusGenerator)
{
super(api);
this.statusGenerator = statusGenerator;
}

@Override
public void afterPropertiesSet() throws Exception
{
super.afterPropertiesSet();
Objects.requireNonNull(statusGenerator, "statusGenerator");
}

@Override
protected void doExecute(DelegateExecution delegateExecution, Variables variables)
{
String recipient = variables.getTarget().getOrganizationIdentifierValue();
String reportLocation = variables
.getString(ConstantsReport.BPMN_EXECUTION_VARIABLE_REPORT_SEARCH_BUNDLE_RESPONSE_REFERENCE);

logger.info("Report dry-run successful for HRP '{}' at '{}' and task with id '{}'", recipient, reportLocation,
variables.getStartTask().getId());
sendSuccessfulMail(recipient, reportLocation);

addOutputToStartTask(variables);
}

private void sendSuccessfulMail(String recipient, String reportLocation)
{
String subject = "New successful dry-run report in process '" + ConstantsReport.PROCESS_NAME_FULL_REPORT_SEND
+ "'";
String message = "A new report has been successfully created as dry-run for HRP '" + recipient
+ "' in process '" + ConstantsReport.PROCESS_NAME_FULL_REPORT_SEND
+ "' and can be accessed using the following link:\n" + "- " + reportLocation;

api.getMailService().send(subject, message);
}

private void addOutputToStartTask(Variables variables)
{
Task task = variables.getStartTask();
task.addOutput(
statusGenerator.createReportStatusOutput(ConstantsReport.CODESYSTEM_REPORT_STATUS_VALUE_DRY_RUN));

variables.updateTask(task);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.function.Supplier;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Endpoint;
import org.hl7.fhir.r4.model.Identifier;
Expand Down Expand Up @@ -56,6 +57,12 @@ protected void doExecute(DelegateExecution execution, Variables variables)

Target target = variables.createTarget(hrpIdentifier, endpointIdentifier, endpoint.getAddress());
variables.setTarget(target);

boolean isDryRun = isDryRun(variables);
if (isDryRun)
logger.info("Creating new report as dry-run for HRP '{}'", hrpIdentifier);

variables.setBoolean(ConstantsReport.BPMN_EXECUTION_VARIABLE_IS_DRY_RUN, isDryRun);
}

private Optional<String> extractHrpIdentifierFromTask(Task task)
Expand Down Expand Up @@ -136,4 +143,13 @@ private String extractEndpointIdentifier(Endpoint endpoint)
.orElseThrow(() -> new RuntimeException("Endpoint with id '" + endpoint.getId()
+ "' is missing identifier with system '" + NamingSystems.EndpointIdentifier.SID + "'"));
}

private boolean isDryRun(Variables variables)
{
return api.getTaskHelper()
.getFirstInputParameterValue(variables.getStartTask(), ConstantsReport.CODESYSTEM_REPORT,
ConstantsReport.CODESYSTEM_REPORT_VALUE_DRY_RUN, BooleanType.class)
.map(BooleanType::booleanValue).orElse(false);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ public class FhirClientConfig
@Value("${de.medizininformatik.initiative.report.dic.fhir.dataLoggingEnabled:false}")
private boolean fhirDataLoggingEnabled;

@ProcessDocumentation(processNames = {
"medizininformatik-initiativede_reportSend" }, description = "Initial Result polling interval in milliseconds for asynchronous request pattern when executing search bundle requests, the interval will be increased tenfold after every check if a result is not ready")
@Value("${de.medizininformatik.initiative.report.dic.fhir.server.async.polling.interval:100}")
private int fhirAsyncInitialPollingIntervalMilliseconds;

@Value("${dev.dsf.bpe.fhir.server.organization.identifier.value}")
private String localIdentifierValue;

Expand All @@ -175,7 +180,8 @@ public FhirClientFactory fhirClientFactory()
return new FhirClientFactory(trustStorePath, certificatePath, privateKeyPath, fhirStorePrivateKeyPassword,
fhirStoreConnectTimeout, fhirStoreSocketTimeout, fhirStoreConnectionRequestTimeout, fhirStoreBaseUrl,
fhirStoreUsername, fhirStorePassword, fhirStoreBearerToken, tokenProvider(), proxyUrl, proxyUsername,
proxyPassword, fhirStoreHapiClientVerbose, fhirContext, localIdentifierValue, dataLogger());
proxyPassword, fhirStoreHapiClientVerbose, fhirAsyncInitialPollingIntervalMilliseconds, fhirContext,
localIdentifierValue, dataLogger());
}

public TokenProvider tokenProvider()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import de.medizininformatik_initiative.process.report.service.DownloadSearchBundle;
import de.medizininformatik_initiative.process.report.service.HandleError;
import de.medizininformatik_initiative.process.report.service.InsertReport;
import de.medizininformatik_initiative.process.report.service.LogDryRun;
import de.medizininformatik_initiative.process.report.service.SelectTargetDic;
import de.medizininformatik_initiative.process.report.service.SelectTargetHrp;
import de.medizininformatik_initiative.process.report.service.SetTimer;
Expand All @@ -42,6 +43,11 @@ public class ReportConfig
@Value("${de.medizininformatik.initiative.report.dic.hrp.identifier:#{null}}")
private String hrpIdentifier;

@ProcessDocumentation(processNames = {
"medizininformatik-initiativede_reportSend" }, description = "To enable asynchronous request pattern when executing search bundle requests set to `true`")
@Value("${de.medizininformatik.initiative.report.dic.fhir.server.async.enabled:false}")
private boolean fhirAsyncEnabled;

// all Processes

@Bean
Expand Down Expand Up @@ -110,10 +116,17 @@ public SearchQueryCheckService searchQueryCheckService()
public CreateReport createReport()
{
String resourceVersion = new ReportProcessPluginDefinition().getResourceVersion();
return new CreateReport(api, resourceVersion, fhirClientConfig.fhirClientFactory(),
return new CreateReport(api, resourceVersion, fhirClientConfig.fhirClientFactory(), fhirAsyncEnabled,
fhirClientConfig.dataLogger());
}

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public LogDryRun logDryRun()
{
return new LogDryRun(api, reportStatusGenerator());
}

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public SendReport sendReport()
Expand Down
Loading
Loading