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

Feature/add mainzelliste client #6

Merged
merged 13 commits into from
May 25, 2022
Prev Previous commit
Next Next commit
Add Mainzelliste support
  • Loading branch information
[email protected] committed Apr 26, 2022
commit a73e187d821911dabab6d7cc6c483523c03e53e2
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,11 @@
<artifactId>mainzelliste-client</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>

</dependencies>
</project>
6 changes: 4 additions & 2 deletions src/docker/adt2fhir.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
file_path=/adt2fhir/clinical_data
store_path=http://host.docker.internal:8080/fhir
identifier_system=http://dktk.dkfz.de/fhir/onco/core/CodeSystem/PseudonymArtCS
store_path=http://host.docker.internal:8090/fhir
identifier_system=http://dktk.dkfz.de/fhir/onco/core/CodeSystem/PseudonymArtCS
mainzelliste_url=http://host.docker.internal:8080
mainzelliste_apikey=pleaseChangeMe
16 changes: 10 additions & 6 deletions src/main/java/de/samply/adt2fhir/Adt2fhir.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ public static void main(String[] args) throws TransformerConfigurationException,
System.out.print("initialize transformers... ");
final TransformerFactoryImpl factory = (TransformerFactoryImpl) TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", null);
net.sf.saxon.Configuration saxonConfig = factory.getConfiguration();
((Processor) saxonConfig.getProcessor()).registerExtensionFunction(new PatientPseudonymizer());
PatientPseudonymizer patientPseudonymizer = new PatientPseudonymizer();
patientPseudonymizer.setConfigReader(configReader);
((Processor) saxonConfig.getProcessor()).registerExtensionFunction(patientPseudonymizer);
((Processor) saxonConfig.getProcessor()).registerExtensionFunction(new UniqueIdGenerator());

final Transformer ADT2singleADTtransformer = factory.newTransformer(new StreamSource(Adt2fhir.class.getClassLoader().getResourceAsStream("toSinglePatients.xsl")));
Expand Down Expand Up @@ -95,9 +97,9 @@ private static void processXmlFiles (String inputData, Transformer transformer,
else {
int counter=1;
for (File inputFile : listOfFiles) {
System.out.println("\u001B[AFile "+counter+" of "+listOfFiles.length);
counter+=1;
if (inputFile.isFile() & inputFile.getName().toLowerCase().endsWith(".xml")) {
System.out.println("\u001B[AFile "+counter+" of "+(listOfFiles.length-1));
counter+=1;
if (transformer ==null){
try {
postToFhirStore(inputFile, httppost);
Expand All @@ -109,17 +111,19 @@ private static void processXmlFiles (String inputData, Transformer transformer,
}
else {
//System.out.print("processing file " + inputFile.getName() + "...");
String combinedADTfile = null;
String inputXml = null;
try {
combinedADTfile = new String(Files.readAllBytes(Paths.get(String.valueOf(inputFile))), StandardCharsets.UTF_8);
inputXml = new String(Files.readAllBytes(Paths.get(String.valueOf(inputFile))), StandardCharsets.UTF_8);
} catch (IOException e) {
counter-=1;
System.out.print("ERROR - reading: problem with file " + inputFile);
e.printStackTrace();
}
try {
String xmlResult = applyXslt(combinedADTfile, transformer);
transformer.setParameter("customPrefix", inputFile.getName());
String xmlResult = applyXslt(inputXml, transformer);
if(transformWrittenResults){
transformer2.setParameter("customPrefix", inputFile.getName());
applyXslt(xmlResult, transformer2);
inputFile.deleteOnExit();
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/de/samply/adt2fhir/ConfigReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public class ConfigReader {
public String file_path;
public String store_path;
public String identifier_system;
public String mainzelliste_url;
public String mainzelliste_apikey;

public void init() throws IOException {
try {
Expand All @@ -31,6 +33,8 @@ public void init() throws IOException {
this.file_path = prop.getProperty("file_path");
this.store_path = prop.getProperty("store_path");
this.identifier_system = prop.getProperty("identifier_system");
this.mainzelliste_url = prop.getProperty("mainzelliste_url");
this.mainzelliste_apikey = prop.getProperty("mainzelliste_apikey");
} catch (IOException e) {
e.printStackTrace();
}
Expand All @@ -45,4 +49,8 @@ public String getStore_path() {
public String getIdentifier_system() {
return identifier_system;
}
public String getMainzelliste_url() { return mainzelliste_url; }
public String getMainzelliste_apikey() {
return mainzelliste_apikey;
}
}
88 changes: 72 additions & 16 deletions src/main/java/de/samply/adt2fhir/PatientPseudonymizer.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package de.samply.adt2fhir;

import de.pseudonymisierung.mainzelliste.client.InvalidSessionException;
import de.pseudonymisierung.mainzelliste.client.MainzellisteConnection;
import de.pseudonymisierung.mainzelliste.client.MainzellisteNetworkException;
import de.pseudonymisierung.mainzelliste.client.Session;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import de.pseudonymisierung.mainzelliste.client.*;
import java.io.*;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
Expand All @@ -14,9 +18,20 @@
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.StringValue;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

public class PatientPseudonymizer extends ExtensionFunctionDefinition {

private String mainzelliste_url;
private String mainzelliste_apikey;
private boolean anonymize;

@Override
public net.sf.saxon.value.SequenceType[] getArgumentTypes() {
Expand Down Expand Up @@ -50,22 +65,63 @@ public Sequence call(XPathContext ctx, Sequence[] args) throws XPathException {
String surname = args[2].iterate().next().getStringValue();
String birthname = args[3].iterate().next().getStringValue();
String brithdate = args[4].iterate().next().getStringValue();
// output = DigestUtils.sha256Hex(gender+prename+surname+birthname+brithdate);//TODO create patientlist call
// More Information on: https://github.com/medicalinformatics/mainzelliste-client
try {
MainzellisteConnection mainzellisteConnection = new MainzellisteConnection("http://localhost:8080", "youReallyShouldChangeMe");
Session session = mainzellisteConnection.createSession();
String addPatientToken = session.getAddPatientToken(null, null);
} catch (MainzellisteNetworkException e) {

} catch (URISyntaxException e) {

} catch (InvalidSessionException e) {
// create new session here
if (mainzelliste_url.isEmpty()) {
output = DigestUtils.sha256Hex(gender + prename + surname + birthname + brithdate).substring(32);
} else {
try {
output=pseudonymizationCall(gender, prename, surname, birthname, brithdate);
} catch (URISyntaxException | MainzellisteNetworkException | InvalidSessionException | IOException e) {
e.printStackTrace();
}
}
return StringValue.makeStringValue(output);
}

};
}

private String pseudonymizationCall(String gender, String prename, String surname, String birthname, String brithdate) throws URISyntaxException, MainzellisteNetworkException, InvalidSessionException, IOException {
String pseudonym="";
String[] brithdateParts = brithdate.split("[.]");
MainzellisteConnection mainzellisteConnection = new MainzellisteConnection(mainzelliste_url, mainzelliste_apikey);
Session session = mainzellisteConnection.createSession();
AddPatientToken token = new AddPatientToken();
token.addIdType("pid");
String addPatientToken = session.getToken(token);
HttpPost httppost = new HttpPost(mainzelliste_url+"/patients?tokenId="+addPatientToken);
httppost.addHeader("content-type", "application/x-www-form-urlencoded");
httppost.addHeader("mainzellisteApiVersion", "3.2");
List<NameValuePair> idat = new ArrayList<NameValuePair>();
//idat.add(new BasicNameValuePair("gender", gender));
idat.add(new BasicNameValuePair("vorname", prename));
idat.add(new BasicNameValuePair("nachname", surname));
idat.add(new BasicNameValuePair("geburtsname", birthname));
idat.add(new BasicNameValuePair("geburtstag", brithdateParts[0]));
idat.add(new BasicNameValuePair("geburtsmonat", brithdateParts[1]));
idat.add(new BasicNameValuePair("geburtsjahr", brithdateParts[2]));
//idat.add(new BasicNameValuePair("plz", ""));
//idat.add(new BasicNameValuePair("ort", ""));
idat.add(new BasicNameValuePair("sureness", "true"));
httppost.setEntity(new UrlEncodedFormEntity(idat, HTTP.UTF_8));
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpResponse response = httpclient.execute(httppost);
if (response.getStatusLine().getStatusCode()!=201) {
System.out.println("Error - Pseudonymization response: " + response.getStatusLine().getStatusCode());
}
String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
httpclient.close();

JsonArray ids = new Gson ().fromJson(responseBody, JsonArray.class);
if(!ids.isEmpty()){
JsonObject id = ids.get(0).getAsJsonObject();
pseudonym=id.getAsJsonPrimitive("idString").getAsString();
}
return pseudonym;
}

public void setConfigReader (ConfigReader configReader){
this.mainzelliste_url=configReader.getMainzelliste_url();
this.mainzelliste_apikey=configReader.getMainzelliste_apikey();
}
}
3 changes: 2 additions & 1 deletion src/main/resources/MDS2FHIR.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:param name="filepath" />
<xsl:param name="customPrefix" />

<xsl:template match="/">

Expand All @@ -37,7 +38,7 @@
<xsl:template match="Patient" mode="patient">
<xsl:variable name="Patient_ID" select="@Patient_ID" />
<xsl:variable name="Vitalstatus_ID" select="hash:hash($Patient_ID, 'vitalstatus', '')" />
<xsl:result-document href="file:{$filepath}/FHIR_Patients/Bundle_{$Patient_ID}.xml">
<xsl:result-document href="file:{$filepath}/FHIR_Patients/Bundle_{$customPrefix}{$Patient_ID}.xml">
<Bundle xmlns="http://hl7.org/fhir">
<id value="{generate-id()}" />
<type value="transaction" />
Expand Down
6 changes: 4 additions & 2 deletions src/main/resources/adt2fhir.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
file_path=changeMeToAbsolutePath/adt2fhir/clinical_data
store_path=http://localhost:8080/fhir
identifier_system=http://dktk.dkfz.de/fhir/onco/core/CodeSystem/PseudonymArtCS
store_path=http://localhost:8090/fhir
identifier_system=http://dktk.dkfz.de/fhir/onco/core/CodeSystem/PseudonymArtCS
mainzelliste_url=http://localhost:8080
mainzelliste_apikey=pleaseChangeMe
3 changes: 2 additions & 1 deletion src/main/resources/toSinglePatients.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="filepath" />
<xsl:param name="customPrefix" />

<xsl:template match="/ADT_GEKID">
<xsl:for-each select="Menge_Patient/Patient">
<xsl:result-document method="xml" href="file:{$filepath}/ADT_Patients/Patient_{Patienten_Stammdaten/@Patient_ID}.xml">
<xsl:result-document method="xml" href="file:{$filepath}/ADT_Patients/Patient_{$customPrefix}{Patienten_Stammdaten/@Patient_ID}.xml">
<!--<xsl:result-document method="xml" href="Patient_{Patienten_Stammdaten/@Patient_ID}.xml">-->
<ADT_GEKID Schema_Version="2.2.1">
<xsl:copy-of select="/ADT_GEKID/@*" />
Expand Down