1
0
mirror of https://github.com/pcvolkmer/mv64e-etl-processor synced 2025-09-13 09:02:50 +00:00

4 Commits

3 changed files with 195 additions and 159 deletions

View File

@@ -39,12 +39,14 @@ public class GicsConsentService implements IConsentService {
private final RestTemplate restTemplate;
private final FhirContext fhirContext;
private final GIcsConfigProperties gIcsConfigProperties;
private final String BROAD_CONSENT_PROFILE_URI = "https://www.medizininformatik-initiative.de/fhir/modul-consent/StructureDefinition/mii-pr-consent-einwilligung";
private final String BROAD_CONSENT_POLICY = "urn:oid:2.16.840.1.113883.3.1937.777.24.2.1791";
public GicsConsentService(
GIcsConfigProperties gIcsConfigProperties,
RetryTemplate retryTemplate,
RestTemplate restTemplate,
AppFhirConfig appFhirConfig
GIcsConfigProperties gIcsConfigProperties,
RetryTemplate retryTemplate,
RestTemplate restTemplate,
AppFhirConfig appFhirConfig
) {
this.retryTemplate = retryTemplate;
this.restTemplate = restTemplate;
@@ -54,34 +56,34 @@ public class GicsConsentService implements IConsentService {
}
protected Parameters getFhirRequestParameters(
String personIdentifierValue
String personIdentifierValue
) {
var result = new Parameters();
result.addParameter(
new ParametersParameterComponent()
.setName("personIdentifier")
.setValue(
new Identifier()
.setValue(personIdentifierValue)
.setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem())
)
new ParametersParameterComponent()
.setName("personIdentifier")
.setValue(
new Identifier()
.setValue(personIdentifierValue)
.setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem())
)
);
result.addParameter(
new ParametersParameterComponent()
.setName("domain")
.setValue(
new StringType()
.setValue(this.gIcsConfigProperties.getBroadConsentDomainName())
)
new ParametersParameterComponent()
.setName("domain")
.setValue(
new StringType()
.setValue(this.gIcsConfigProperties.getBroadConsentDomainName())
)
);
result.addParameter(
new ParametersParameterComponent()
.setName("policy")
.setValue(
new Coding()
.setCode(this.gIcsConfigProperties.getBroadConsentPolicyCode())
.setSystem(this.gIcsConfigProperties.getBroadConsentPolicySystem())
)
new ParametersParameterComponent()
.setName("policy")
.setValue(
new Coding()
.setCode(this.gIcsConfigProperties.getBroadConsentPolicyCode())
.setSystem(this.gIcsConfigProperties.getBroadConsentPolicySystem())
)
);
/*
@@ -89,10 +91,10 @@ public class GicsConsentService implements IConsentService {
* 'ignoreVersionNumber'.
*/
result.addParameter(
new ParametersParameterComponent()
.setName("version")
.setValue(new StringType().setValue("1.1")
)
new ParametersParameterComponent()
.setName("version")
.setValue(new StringType().setValue("1.1")
)
);
/* add config parameter with:
@@ -101,17 +103,17 @@ public class GicsConsentService implements IConsentService {
* unknownStateIsConsideredAsDecline -> true
*/
var config = new ParametersParameterComponent()
.setName("config")
.addPart(
new ParametersParameterComponent()
.setName("ignoreVersionNumber")
.setValue(new BooleanType().setValue(true))
)
.addPart(
new ParametersParameterComponent()
.setName("unknownStateIsConsideredAsDecline")
.setValue(new BooleanType().setValue(false))
);
.setName("config")
.addPart(
new ParametersParameterComponent()
.setName("ignoreVersionNumber")
.setValue(new BooleanType().setValue(true))
)
.addPart(
new ParametersParameterComponent()
.setName("unknownStateIsConsideredAsDecline")
.setValue(new BooleanType().setValue(false))
);
result.addParameter(config);
@@ -130,8 +132,8 @@ public class GicsConsentService implements IConsentService {
headers.setContentType(MediaType.APPLICATION_XML);
if (
StringUtils.isBlank(this.gIcsConfigProperties.getUsername())
|| StringUtils.isBlank(this.gIcsConfigProperties.getPassword())
StringUtils.isBlank(this.gIcsConfigProperties.getUsername())
|| StringUtils.isBlank(this.gIcsConfigProperties.getPassword())
) {
return headers;
}
@@ -145,28 +147,28 @@ public class GicsConsentService implements IConsentService {
HttpEntity<String> requestEntity = new HttpEntity<>(parameterAsXml, this.headersWithHttpBasicAuth());
try {
var responseEntity = retryTemplate.execute(
ctx -> restTemplate.exchange(endpointUri(endpoint), HttpMethod.POST, requestEntity, String.class)
ctx -> restTemplate.exchange(endpointUri(endpoint), HttpMethod.POST, requestEntity, String.class)
);
if (responseEntity.getStatusCode().is2xxSuccessful()) {
return responseEntity.getBody();
} else {
var msg = String.format(
"Trusted party system reached but request failed! code: '%s' response: '%s'",
responseEntity.getStatusCode(), responseEntity.getBody());
"Trusted party system reached but request failed! code: '%s' response: '%s'",
responseEntity.getStatusCode(), responseEntity.getBody());
log.error(msg);
return null;
}
} catch (RestClientException e) {
var msg = String.format("Get consents status request failed reason: '%s",
e.getMessage());
e.getMessage());
log.error(msg);
return null;
} catch (TerminatedRetryException terminatedRetryException) {
var msg = String.format(
"Get consents status process has been terminated. termination reason: '%s",
terminatedRetryException.getMessage());
"Get consents status process has been terminated. termination reason: '%s",
terminatedRetryException.getMessage());
log.error(msg);
return null;
}
@@ -175,45 +177,45 @@ public class GicsConsentService implements IConsentService {
@Override
public TtpConsentStatus getTtpBroadConsentStatus(String personIdentifierValue) {
var consentStatusResponse = callGicsApi(
getFhirRequestParameters(personIdentifierValue),
GicsConsentService.IS_CONSENTED_ENDPOINT
getFhirRequestParameters(personIdentifierValue),
GicsConsentService.IS_CONSENTED_ENDPOINT
);
return evaluateConsentResponse(consentStatusResponse);
}
protected Bundle currentConsentForPersonAndTemplate(
String personIdentifierValue,
ConsentDomain consentDomain,
Date requestDate
String personIdentifierValue,
ConsentDomain consentDomain,
Date requestDate
) {
var requestParameter = buildRequestParameterCurrentPolicyStatesForPerson(
personIdentifierValue,
requestDate,
consentDomain
personIdentifierValue,
requestDate,
consentDomain
);
var consentDataSerialized = callGicsApi(requestParameter,
GicsConsentService.IS_POLICY_STATES_FOR_PERSON_ENDPOINT);
GicsConsentService.IS_POLICY_STATES_FOR_PERSON_ENDPOINT);
if (consentDataSerialized == null) {
// error occurred - should not process further!
throw new IllegalStateException(
"consent data request failed - stopping processing! - try again or fix other problems first.");
"consent data request failed - stopping processing! - try again or fix other problems first.");
}
var iBaseResource = fhirContext.newJsonParser()
.parseResource(consentDataSerialized);
.parseResource(consentDataSerialized);
if (iBaseResource instanceof OperationOutcome) {
// log error - very likely a configuration error
String errorMessage =
"Consent request failed! Check outcome:\n " + consentDataSerialized;
"Consent request failed! Check outcome:\n " + consentDataSerialized;
log.error(errorMessage);
throw new IllegalStateException(errorMessage);
} else if (iBaseResource instanceof Bundle bundle) {
return bundle;
} else {
String errorMessage = "Consent request failed! Unexpected response received! -> "
+ consentDataSerialized;
+ consentDataSerialized;
log.error(errorMessage);
throw new IllegalStateException(errorMessage);
}
@@ -228,43 +230,43 @@ public class GicsConsentService implements IConsentService {
}
protected Parameters buildRequestParameterCurrentPolicyStatesForPerson(
String personIdentifierValue,
Date requestDate,
ConsentDomain consentDomain
String personIdentifierValue,
Date requestDate,
ConsentDomain consentDomain
) {
var requestParameter = new Parameters();
requestParameter.addParameter(
new ParametersParameterComponent()
.setName("personIdentifier")
.setValue(
new Identifier()
.setValue(personIdentifierValue)
.setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem())
)
new ParametersParameterComponent()
.setName("personIdentifier")
.setValue(
new Identifier()
.setValue(personIdentifierValue)
.setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem())
)
);
requestParameter.addParameter(
new ParametersParameterComponent()
.setName("domain")
.setValue(new StringType().setValue(getConsentDomainName(consentDomain)))
new ParametersParameterComponent()
.setName("domain")
.setValue(new StringType().setValue(getConsentDomainName(consentDomain)))
);
Parameters nestedConfigParameters = new Parameters();
nestedConfigParameters
.addParameter(
new ParametersParameterComponent()
.setName("idMatchingType")
.setValue(new Coding()
.setSystem("https://ths-greifswald.de/fhir/CodeSystem/gics/IdMatchingType")
.setCode("AT_LEAST_ONE")
)
)
.addParameter("ignoreVersionNumber", false)
.addParameter("unknownStateIsConsideredAsDecline", false)
.addParameter("requestDate", new DateType().setValue(requestDate));
.addParameter(
new ParametersParameterComponent()
.setName("idMatchingType")
.setValue(new Coding()
.setSystem("https://ths-greifswald.de/fhir/CodeSystem/gics/IdMatchingType")
.setCode("AT_LEAST_ONE")
)
)
.addParameter("ignoreVersionNumber", false)
.addParameter("unknownStateIsConsideredAsDecline", false)
.addParameter("requestDate", new DateType().setValue(requestDate));
requestParameter.addParameter(
new ParametersParameterComponent().setName("config").addPart().setResource(nestedConfigParameters)
new ParametersParameterComponent().setName("config").addPart().setResource(nestedConfigParameters)
);
return requestParameter;
@@ -291,7 +293,7 @@ public class GicsConsentService implements IConsentService {
}
} else if (response instanceof OperationOutcome outcome) {
log.error("failed to get consent status from ttp. probably configuration error. "
+ "outcome: '{}'", fhirContext.newJsonParser().encodeToString(outcome));
+ "outcome: '{}'", fhirContext.newJsonParser().encodeToString(outcome));
}
} catch (DataFormatException dfe) {
@@ -302,6 +304,36 @@ public class GicsConsentService implements IConsentService {
@Override
public Bundle getConsent(String patientId, Date requestDate, ConsentDomain consentDomain) {
return currentConsentForPersonAndTemplate(patientId, consentDomain, requestDate);
Bundle gIcsResultBundle = currentConsentForPersonAndTemplate(patientId, consentDomain, requestDate);
if (ConsentDomain.BROAD_CONSENT == consentDomain) {
return convertGicsResultToMiiBroadConsent(gIcsResultBundle);
}
return gIcsResultBundle;
}
protected Bundle convertGicsResultToMiiBroadConsent(Bundle gIcsResultBundle) {
if (gIcsResultBundle == null
|| gIcsResultBundle.getEntry().isEmpty()
|| !(gIcsResultBundle.getEntry().getFirst().getResource() instanceof Consent))
return gIcsResultBundle;
Bundle.BundleEntryComponent bundleEntryComponent = gIcsResultBundle.getEntry().getFirst();
var consentAsOne = (Consent) bundleEntryComponent.getResource();
if (consentAsOne.getPolicy().stream().noneMatch(p -> p.getUri().equals(BROAD_CONSENT_POLICY))) {
consentAsOne.addPolicy(new Consent.ConsentPolicyComponent().setUri(BROAD_CONSENT_POLICY));
}
if (consentAsOne.getMeta().getProfile().stream().noneMatch(p -> p.getValue().equals(BROAD_CONSENT_PROFILE_URI))) {
consentAsOne.getMeta().addProfile(BROAD_CONSENT_PROFILE_URI);
}
consentAsOne.setPolicyRule(null);
gIcsResultBundle.getEntry().stream().skip(1).forEach(c -> consentAsOne.getProvision().addProvision(((Consent) c.getResource()).getProvision().getProvisionFirstRep()));
gIcsResultBundle.getEntry().clear();
gIcsResultBundle.addEntry(bundleEntryComponent);
return gIcsResultBundle;
}
}

View File

@@ -24,14 +24,15 @@ import java.time.Instant;
import java.util.Date;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withServerError;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@ContextConfiguration(classes = {AppConfiguration.class, ObjectMapper.class})
@TestPropertySource(properties = {
"app.consent.service=gics",
"app.consent.gics.uri=http://localhost:8090/ttp-fhir/fhir/gics"
"app.consent.service=gics",
"app.consent.gics.uri=http://localhost:8090/ttp-fhir/fhir/gics"
})
@RestClientTest
class GicsConsentServiceTest {
@@ -46,8 +47,8 @@ class GicsConsentServiceTest {
@BeforeEach
void setUp(
@Autowired AppFhirConfig appFhirConfig,
@Autowired GIcsConfigProperties gIcsConfigProperties
@Autowired AppFhirConfig appFhirConfig,
@Autowired GIcsConfigProperties gIcsConfigProperties
) {
this.appFhirConfig = appFhirConfig;
this.gIcsConfigProperties = gIcsConfigProperties;
@@ -56,33 +57,33 @@ class GicsConsentServiceTest {
this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate);
this.gicsConsentService = new GicsConsentService(
this.gIcsConfigProperties,
RetryTemplate.builder().maxAttempts(1).build(),
restTemplate,
this.appFhirConfig
this.gIcsConfigProperties,
RetryTemplate.builder().maxAttempts(1).build(),
restTemplate,
this.appFhirConfig
);
}
@Test
void shouldReturnTtpBroadConsentStatus() {
final Parameters consentedResponse = new Parameters()
.addParameter(
new ParametersParameterComponent()
.setName("consented")
.setValue(new BooleanType().setValue(true))
);
.addParameter(
new ParametersParameterComponent()
.setName("consented")
.setValue(new BooleanType().setValue(true))
);
mockRestServiceServer
.expect(
requestTo(
"http://localhost:8090/ttp-fhir/fhir/gics" + GicsConsentService.IS_CONSENTED_ENDPOINT)
)
.andRespond(
withSuccess(
appFhirConfig.fhirContext().newJsonParser().encodeResourceToString(consentedResponse),
MediaType.APPLICATION_JSON
.expect(
requestTo(
"http://localhost:8090/ttp-fhir/fhir/gics" + GicsConsentService.IS_CONSENTED_ENDPOINT)
)
);
.andRespond(
withSuccess(
appFhirConfig.fhirContext().newJsonParser().encodeResourceToString(consentedResponse),
MediaType.APPLICATION_JSON
)
);
var consentStatus = gicsConsentService.getTtpBroadConsentStatus("123456");
assertThat(consentStatus).isEqualTo(TtpConsentStatus.BROAD_CONSENT_GIVEN);
@@ -91,22 +92,22 @@ class GicsConsentServiceTest {
@Test
void shouldReturnRevokedConsent() {
final Parameters revokedResponse = new Parameters()
.addParameter(
new ParametersParameterComponent()
.setName("consented")
.setValue(new BooleanType().setValue(false))
);
.addParameter(
new ParametersParameterComponent()
.setName("consented")
.setValue(new BooleanType().setValue(false))
);
mockRestServiceServer
.expect(
requestTo(
"http://localhost:8090/ttp-fhir/fhir/gics" + GicsConsentService.IS_CONSENTED_ENDPOINT)
)
.andRespond(
withSuccess(
appFhirConfig.fhirContext().newJsonParser().encodeResourceToString(revokedResponse),
MediaType.APPLICATION_JSON)
);
.expect(
requestTo(
"http://localhost:8090/ttp-fhir/fhir/gics" + GicsConsentService.IS_CONSENTED_ENDPOINT)
)
.andRespond(
withSuccess(
appFhirConfig.fhirContext().newJsonParser().encodeResourceToString(revokedResponse),
MediaType.APPLICATION_JSON)
);
var consentStatus = gicsConsentService.getTtpBroadConsentStatus("123456");
assertThat(consentStatus).isEqualTo(TtpConsentStatus.BROAD_CONSENT_MISSING_OR_REJECTED);
@@ -116,23 +117,23 @@ class GicsConsentServiceTest {
@Test
void shouldReturnInvalidParameterResponse() {
final OperationOutcome responseWithErrorOutcome = new OperationOutcome()
.addIssue(
new OperationOutcomeIssueComponent()
.setSeverity(IssueSeverity.ERROR)
.setCode(IssueType.PROCESSING)
.setDiagnostics("Invalid policy parameter...")
);
.addIssue(
new OperationOutcomeIssueComponent()
.setSeverity(IssueSeverity.ERROR)
.setCode(IssueType.PROCESSING)
.setDiagnostics("Invalid policy parameter...")
);
mockRestServiceServer
.expect(
requestTo(GICS_BASE_URI + GicsConsentService.IS_CONSENTED_ENDPOINT)
)
.andRespond(
withSuccess(
appFhirConfig.fhirContext().newJsonParser().encodeResourceToString(responseWithErrorOutcome),
MediaType.APPLICATION_JSON
.expect(
requestTo(GICS_BASE_URI + GicsConsentService.IS_CONSENTED_ENDPOINT)
)
);
.andRespond(
withSuccess(
appFhirConfig.fhirContext().newJsonParser().encodeResourceToString(responseWithErrorOutcome),
MediaType.APPLICATION_JSON
)
);
var consentStatus = gicsConsentService.getTtpBroadConsentStatus("123456");
assertThat(consentStatus).isEqualTo(TtpConsentStatus.FAILED_TO_ASK);
@@ -141,12 +142,12 @@ class GicsConsentServiceTest {
@Test
void shouldReturnRequestError() {
mockRestServiceServer
.expect(
requestTo(GICS_BASE_URI + GicsConsentService.IS_CONSENTED_ENDPOINT)
)
.andRespond(
withServerError()
);
.expect(
requestTo(GICS_BASE_URI + GicsConsentService.IS_CONSENTED_ENDPOINT)
)
.andRespond(
withServerError()
);
var consentStatus = gicsConsentService.getTtpBroadConsentStatus("123456");
assertThat(consentStatus).isEqualTo(TtpConsentStatus.FAILED_TO_ASK);
@@ -156,26 +157,29 @@ class GicsConsentServiceTest {
void buildRequestParameterCurrentPolicyStatesForPersonTest() {
String pid = "12345678";
var result = gicsConsentService
.buildRequestParameterCurrentPolicyStatesForPerson(
pid,
Date.from(Instant.now()),
ConsentDomain.MODELLVORHABEN_64E
);
.buildRequestParameterCurrentPolicyStatesForPerson(
pid,
Date.from(Instant.now()),
ConsentDomain.MODELLVORHABEN_64E
);
assertThat(result.getParameter())
.as("should contain 3 parameter resources")
.hasSize(3);
.as("should contain 3 parameter resources")
.hasSize(3);
assertThat(((StringType) result.getParameter("domain").getValue()).getValue())
.isEqualTo(
gIcsConfigProperties.getGenomDeConsentDomainName()
);
.isEqualTo(
gIcsConfigProperties.getGenomDeConsentDomainName()
);
assertThat(((Identifier) result.getParameter("personIdentifier").getValue()).getValue())
.isEqualTo(
pid
);
.isEqualTo(
pid
);
}
@Test
public void convertGicsResultToMiiBroadConsent() {
fail("todo: implement Test gicsConsentService.convertGicsResultToMiiBroadConsent");
}
}

View File

@@ -80,7 +80,7 @@ class ConsentProcessorTest {
val checkResult = consentProcessor.consentGatedCheckAndTryEmbedding(inputMtb)
assertThat(checkResult).isTrue
assertThat(inputMtb.metadata.researchConsents).hasSize(26)
assertThat(inputMtb.metadata.researchConsents).isNotEmpty
}
companion object {