Skip to content

Commit

Permalink
Merge pull request #105 from medizininformatik-initiative/release-1.0…
Browse files Browse the repository at this point in the history
….0.4

Release Version 1.0.0.4
  • Loading branch information
EmteZogaf committed Jan 16, 2024
2 parents 0afdbee + 4ed77d0 commit 6a35edf
Show file tree
Hide file tree
Showing 13 changed files with 459 additions and 54 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ jobs:
- name: Release
uses: softprops/action-gh-release@v1
with:
files: feasibility-dsf-process/target/feasibility-dsf-process-*.jar
draft: true
generate_release_notes: true
files: |
feasibility-dsf-process/target/feasibility-dsf-process-*.jar
feasibility-dsf-process/target/feasibility-dsf-process-*.jar.sha256
name: "Feasibility DSF Process - v${{ steps.prep.outputs.version }}"

29 changes: 26 additions & 3 deletions feasibility-dsf-process/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,25 @@
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.18.3</version>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>nginx</artifactId>
<version>1.18.3</version>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>toxiproxy</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.18.3</version>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -178,6 +184,23 @@
</executions>
</plugin>

<plugin>
<groupId>net.nicoulaj.maven.plugins</groupId>
<artifactId>checksum-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>artifacts</goal>
</goals>
</execution>
</executions>
<configuration>
<algorithms>
<algorithm>SHA-256</algorithm>
</algorithms>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.message.BasicHeader;
Expand All @@ -11,6 +12,7 @@
import java.net.URI;

import static ca.uhn.fhir.rest.api.Constants.HEADER_CONTENT_TYPE;
import static java.lang.String.format;

/**
* Client for communicating with a Flare instance.
Expand All @@ -31,19 +33,28 @@ public int requestFeasibility(byte[] structuredQuery) throws IOException, Interr
req.setEntity(new ByteArrayEntity(structuredQuery));
req.setHeader(new BasicHeader(HEADER_CONTENT_TYPE, "application/sq+json"));

var response = httpClient.execute(req, new BasicResponseHandler());
var response = sendRequest(req);

return Integer.parseInt(response);
}

private URI resolve(String path) {
return flareBaseUrl.resolve((flareBaseUrl.getPath() + path).replaceAll("//", "/"));
}

@Override
public void testConnection() throws IOException {
var req = new HttpGet(resolve("/cache/stats"));

httpClient.execute(req, new BasicResponseHandler());
sendRequest(req);
}

private URI resolve(String path) {
return flareBaseUrl.resolve((flareBaseUrl.getPath() + path).replaceAll("//", "/"));
}

private String sendRequest(HttpUriRequest req) throws IOException {
try {
return httpClient.execute(req, new BasicResponseHandler());
} catch (IOException e) {
throw new IOException(
format("Error sending %s request to flare webservice url '%s'.", req.getMethod(), req.getURI()), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,11 @@ private FlareWebserviceClient createFlareClient(HttpClient httpClient) {
public HttpClient flareHttpClient(@Qualifier("base-client") SSLContext sslContext,
EvaluationSettingsProvider evaluationSettingsProvider) {
if (EvaluationStrategy.STRUCTURED_QUERY == evaluationSettingsProvider.evaluationStrategy()) {
HttpClientBuilder builder = new TlsClientFactory(null, sslContext).getNativeHttpClientBuilder();
TlsClientFactory clientFactory = new TlsClientFactory(null, sslContext);
clientFactory.setConnectTimeout(connectTimeout);
clientFactory.setConnectionRequestTimeout(connectTimeout);
clientFactory.setSocketTimeout(connectTimeout);
HttpClientBuilder builder = clientFactory.getNativeHttpClientBuilder();

BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import java.util.Objects;

import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.MEASURE_REPORT_PERIOD_END;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.MEASURE_REPORT_PERIOD_START;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.VARIABLE_MEASURE_ID;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.VARIABLE_MEASURE_REPORT;

Expand Down Expand Up @@ -52,8 +54,8 @@ protected void doExecute(DelegateExecution execution, Variables variables) {
private MeasureReport executeEvaluateMeasure(String measureId) {
logger.debug("Evaluate measure {}", measureId);
return storeClient.operation().onInstance("Measure/" + measureId).named("evaluate-measure")
.withParameter(Parameters.class, "periodStart", new DateType(1900, 1, 1))
.andParameter("periodEnd", new DateType(2100, 1, 1))
.withParameter(Parameters.class, "periodStart", new DateType(MEASURE_REPORT_PERIOD_START))
.andParameter("periodEnd", new DateType(MEASURE_REPORT_PERIOD_END))
.useHttpGet()
.returnResourceType(MeasureReport.class)
.execute();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.hl7.fhir.r4.model.MeasureReport.MeasureReportGroupComponent;
import org.hl7.fhir.r4.model.MeasureReport.MeasureReportGroupPopulationComponent;
import org.hl7.fhir.r4.model.Period;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.InitializingBean;

import java.io.IOException;
Expand All @@ -23,6 +22,8 @@

import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.CODESYSTEM_MEASURE_POPULATION;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.CODESYSTEM_MEASURE_POPULATION_VALUE_INITIAL_POPULATION;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.MEASURE_REPORT_PERIOD_END;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.MEASURE_REPORT_PERIOD_START;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.VARIABLE_LIBRARY;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.VARIABLE_MEASURE;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.VARIABLE_MEASURE_REPORT;
Expand Down Expand Up @@ -78,8 +79,8 @@ private MeasureReport buildMeasureReport(String measureRef, int feasibility) {
.setDate(new Date())
.setMeasure(measureRef)
.setPeriod(new Period()
.setStart(new LocalDate(1900, 1, 1).toDate())
.setEnd(new LocalDate(2100, 1, 1).toDate()));
.setStart(MEASURE_REPORT_PERIOD_START)
.setEnd(MEASURE_REPORT_PERIOD_END));

var populationGroup = new MeasureReportGroupPopulationComponent()
.setCount(feasibility)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,23 @@
import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
import dev.dsf.bpe.v1.variables.Variables;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.MeasureReport;
import org.hl7.fhir.r4.model.MeasureReport.MeasureReportGroupPopulationComponent;
import org.hl7.fhir.r4.model.Period;
import org.springframework.beans.factory.InitializingBean;

import java.util.Objects;

import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.CODESYSTEM_MEASURE_POPULATION;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.CODESYSTEM_MEASURE_POPULATION_VALUE_INITIAL_POPULATION;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.MEASURE_REPORT_PERIOD_END;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.MEASURE_REPORT_PERIOD_START;
import static de.medizininformatik_initiative.feasibility_dsf_process.variables.ConstantsFeasibility.VARIABLE_MEASURE_REPORT;
import static java.lang.String.format;
import static org.hl7.fhir.r4.model.MeasureReport.MeasureReportStatus.COMPLETE;
import static org.hl7.fhir.r4.model.MeasureReport.MeasureReportType.SUMMARY;

public class ObfuscateEvaluationResult extends AbstractServiceDelegate
implements InitializingBean {
Expand All @@ -31,15 +42,42 @@ public void afterPropertiesSet() throws Exception {
@Override
protected void doExecute(DelegateExecution execution, Variables variables) {
var measureReport = (MeasureReport) variables.getResource(VARIABLE_MEASURE_REPORT);
variables.setResource(VARIABLE_MEASURE_REPORT, obfuscateFeasibilityCount(measureReport));

if (measureReport.getStatus() == COMPLETE) {
variables.setResource(VARIABLE_MEASURE_REPORT, obfuscateFeasibilityCount(measureReport));
} else {
throw new RuntimeException(format("Expected status '%s' but actually is '%s' for measure report (id '%s').",
COMPLETE, measureReport.getStatus(), measureReport.getId()));
}
}

private MeasureReport obfuscateFeasibilityCount(MeasureReport measureReport) {
var obfuscatedFeasibilityCount = obfuscator.obfuscate(measureReport.getGroupFirstRep().
getPopulationFirstRep().getCount());
var obfuscatedFeasibilityCount = obfuscator.obfuscate(extractInitialPopulation(measureReport).getCount());

var obfuscatedMeasureReport = new MeasureReport()
.setStatus(COMPLETE)
.setType(SUMMARY)
.setMeasure(measureReport.getMeasure())
.setPeriod(new Period()
.setStart(MEASURE_REPORT_PERIOD_START)
.setEnd(MEASURE_REPORT_PERIOD_END));

obfuscatedMeasureReport.getGroupFirstRep().getPopulationFirstRep()
.setCode(new CodeableConcept().addCoding(new Coding().setSystem(CODESYSTEM_MEASURE_POPULATION)
.setCode(CODESYSTEM_MEASURE_POPULATION_VALUE_INITIAL_POPULATION)))
.setCount(obfuscatedFeasibilityCount);

var obfuscatedMeasureReport = measureReport.copy();
obfuscatedMeasureReport.getGroupFirstRep().getPopulationFirstRep().setCount(obfuscatedFeasibilityCount);
return obfuscatedMeasureReport;
}

private MeasureReportGroupPopulationComponent extractInitialPopulation(MeasureReport measureReport) {
return measureReport.getGroupFirstRep().getPopulation().stream()
.filter((p) -> p.getCode().getCoding().stream()
.anyMatch((c) -> c.getSystem().equals(CODESYSTEM_MEASURE_POPULATION) && c.getCode()
.equals(CODESYSTEM_MEASURE_POPULATION_VALUE_INITIAL_POPULATION)))
.findFirst()
.orElseThrow(() -> new RuntimeException(
format("Missing population with coding '%s' in measure report (id '%s').",
CODESYSTEM_MEASURE_POPULATION_VALUE_INITIAL_POPULATION, measureReport.getId())));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package de.medizininformatik_initiative.feasibility_dsf_process.variables;

import org.joda.time.LocalDate;

import java.util.Date;

public interface ConstantsFeasibility {
String VARIABLE_MEASURE = "measure";
String VARIABLE_LIBRARY = "library";
Expand All @@ -23,4 +27,7 @@ public interface ConstantsFeasibility {

String FEASIBILITY_REQUEST_PROCESS_ID = "medizininformatik-initiativede_feasibilityRequest";
String FEASIBILITY_EXECUTE_PROCESS_ID = "medizininformatik-initiativede_feasibilityExecute";

Date MEASURE_REPORT_PERIOD_START = new LocalDate(1900, 1, 1).toDate();
Date MEASURE_REPORT_PERIOD_END = new LocalDate(2100, 1, 1).toDate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.utility.DockerImageName;

import java.net.URL;
Expand All @@ -13,26 +12,27 @@ public abstract class FlareWebserviceClientImplBaseIT {

protected static final Network DEFAULT_CONTAINER_NETWORK = Network.newNetwork();

@Container
public static GenericContainer<?> fhirServer = new GenericContainer<>(
DockerImageName.parse("samply/blaze:0.23.0"))
public static GenericContainer<?> fhirServer = new GenericContainer<>(DockerImageName.parse("samply/blaze:0.23.0"))
.withExposedPorts(8080)
.withNetwork(DEFAULT_CONTAINER_NETWORK)
.withNetworkAliases("fhir-server")
.withEnv("LOG_LEVEL", "debug");

@Container
public static GenericContainer<?> flare = new GenericContainer<>(
DockerImageName.parse("ghcr.io/medizininformatik-initiative/flare:2.1.0"))
public static GenericContainer<?> flare = new GenericContainer<>(DockerImageName.parse("ghcr.io/medizininformatik-initiative/flare:2.1.0"))
.withExposedPorts(8080)
.withNetwork(DEFAULT_CONTAINER_NETWORK)
.withNetworkAliases("flare")
.withEnv(Map.of(
"FLARE_FHIR_SERVER", "http://fhir-server:8080/fhir/"
))
.withEnv(Map.of("FLARE_FHIR_SERVER", "http://fhir-server:8080/fhir/"))
.withStartupTimeout(Duration.ofMinutes(5))
.dependsOn(fhirServer);

static {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
flare.stop();
fhirServer.stop();
}));
}

protected static URL getResource(final String name) {
return FlareWebserviceClientImplBaseIT.class.getResource(name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import java.net.URISyntaxException;
import java.time.Duration;

import static jakarta.ws.rs.HttpMethod.POST;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand All @@ -28,14 +30,16 @@
@ExtendWith(MockitoExtension.class)
public class FlareWebserviceClientImplTest {

private org.apache.http.client.HttpClient httpClient;
private HttpClient httpClient;
private URI flareBaseUrl;
private FlareWebserviceClient flareWebserviceClient;
@Captor ArgumentCaptor<HttpPost> postCaptor;

@BeforeEach
public void setUp() throws URISyntaxException {
httpClient = mock(HttpClient.class);
flareWebserviceClient = new FlareWebserviceClientImpl(httpClient, new URI("http://localhost:5000/"));
flareBaseUrl = new URI("http://localhost:5000/");
flareWebserviceClient = new FlareWebserviceClientImpl(httpClient, flareBaseUrl);
}

@Test
Expand Down Expand Up @@ -134,4 +138,18 @@ void testOtherEvaluationStrategyFails() throws Exception {

assertEquals("EVALUATION_STRATEGY is not set to 'structured-query'.", e.getMessage());
}

@Test
void sendErrorGetsRethrownWithAdditionalInformation() throws Exception {
byte[] structuredQuery = "foo".getBytes();
IOException error = new IOException("error-151930");
when(httpClient.execute(any(HttpPost.class), any(BasicResponseHandler.class))).thenThrow(error);

assertThatThrownBy(() -> {
flareWebserviceClient.requestFeasibility(structuredQuery);
})
.hasMessage("Error sending %s request to flare webservice url '%s'.", POST,
flareBaseUrl.resolve("/query/execute"))
.hasCause(error);
}
}

0 comments on commit 6a35edf

Please sign in to comment.