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/ere 694 vsdm sensor data message #108

Merged
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
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package health.ere.ps.resource.gematik;

import java.net.MalformedURLException;
import java.net.URL;
import de.gematik.ws.conn.vsds.vsdservice.v5.FaultMessage;
import health.ere.ps.config.RuntimeConfig;
import health.ere.ps.config.UserConfig;
import health.ere.ps.service.gematik.PharmacyService;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.r4.model.Bundle;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
Expand All @@ -11,12 +15,6 @@
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import org.hl7.fhir.r4.model.Bundle;

import de.gematik.ws.conn.vsds.vsdservice.v5.FaultMessage;
import health.ere.ps.config.UserConfig;
import health.ere.ps.service.gematik.PharmacyService;

@Path("/pharmacy")
public class PharmacyResource {

Expand Down Expand Up @@ -47,7 +45,9 @@ public Response unsubscribe() throws de.gematik.ws.conn.eventservice.wsdl.v7.Fau
@GET
@Path("Task")
public Bundle task(@QueryParam("egkHandle") String egkHandle, @QueryParam("smcbHandle") String smcbHandle) throws FaultMessage, de.gematik.ws.conn.eventservice.wsdl.v7.FaultMessage {
return pharmacyService.getEPrescriptionsForCardHandle(egkHandle, smcbHandle, ERezeptWorkflowResource.extractRuntimeConfigFromHeaders(httpServletRequest, userConfig));
RuntimeConfig runtimeConfig = ERezeptWorkflowResource.extractRuntimeConfigFromHeaders(httpServletRequest, userConfig);
Pair<Bundle, String> pair = pharmacyService.getEPrescriptionsForCardHandle(egkHandle, smcbHandle, runtimeConfig);
return pair.getKey();
}

@GET
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package health.ere.ps.service.cardlink;

import java.net.URI;
import java.util.logging.Logger;

import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
Expand All @@ -11,19 +8,17 @@
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import java.net.URI;
import java.util.logging.Logger;

@ClientEndpoint(configurator = AddJWTConfigurator.class)
public class CardlinkWebsocketClient {

private static Logger log = Logger.getLogger(CardlinkWebsocketClient.class.getName());
private static final Logger log = Logger.getLogger(CardlinkWebsocketClient.class.getName());

URI endpointURI;
Session userSession;


public CardlinkWebsocketClient() {

}

public CardlinkWebsocketClient(URI endpointURI) {
try {
this.endpointURI = endpointURI;
Expand Down Expand Up @@ -66,15 +61,13 @@ public void onMessage(String message) {
log.info(message);
}



/**
* Send a message.
*
* @param message
* @param message String
*/
public void sendMessage(String message) {
log.info(message);
this.userSession.getAsyncRemote().sendText(message);
}

}
37 changes: 24 additions & 13 deletions src/main/java/health/ere/ps/service/cetp/CETPServer.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
package health.ere.ps.service.cetp;

import java.net.InetAddress;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.net.ssl.SSLContext;

import org.wildfly.common.net.Inet;

import health.ere.ps.config.AppConfig;
import health.ere.ps.service.cardlink.CardlinkWebsocketClient;
import health.ere.ps.service.cetp.codec.CETPDecoder;
import health.ere.ps.service.common.security.SecretsManagerService;
import health.ere.ps.service.gematik.PharmacyService;
Expand All @@ -28,10 +18,17 @@
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;

@ApplicationScoped
public class CETPServer {
public static final int PORT = 8585;
Expand Down Expand Up @@ -63,7 +60,21 @@ void onShutdown(@Observes ShutdownEvent ev) {
if(bossGroup != null) {
bossGroup.shutdownGracefully();
}
}

private URI getCardLinkURI() {
URI cardLinkURI = null;
try {
String cardLinkServer = appConfig
.getCardLinkServer()
.orElse("wss:https://cardlink.service-health.de:8444/websocket/80276003650110006580-20230112");

log.info("Starting websocket connection to: " + cardLinkServer);
cardLinkURI = new URI(cardLinkServer);
} catch (URISyntaxException e) {
log.log(Level.WARNING, "Could not connect to card link", e);
}
return cardLinkURI;
}

public void run() {
Expand All @@ -87,7 +98,7 @@ public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast("ssl", sslContext.newHandler(ch.alloc()))
.addLast(new CETPDecoder())
.addLast(new CETPServerHandler(pharmacyService, appConfig.getCardLinkServer().orElse("wss:https://cardlink.service-health.de:8444/websocket/80276003650110006580-20230112")));
.addLast(new CETPServerHandler(pharmacyService, new CardlinkWebsocketClient(getCardLinkURI())));
} catch (Exception e) {
log.log(Level.WARNING, "Failed to create SSL context", e);
}
Expand Down
163 changes: 89 additions & 74 deletions src/main/java/health/ere/ps/service/cetp/CETPServerHandler.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
package health.ere.ps.service.cetp;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.xml.bind.DatatypeConverter;

import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import de.gematik.ws.conn.eventservice.v7.Event;
Expand All @@ -23,104 +9,133 @@
import health.ere.ps.service.gematik.PharmacyService;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.xml.bind.DatatypeConverter;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CETPServerHandler extends ChannelInboundHandlerAdapter {

private static final Logger log = Logger.getLogger(CETPServerHandler.class.getName());

PharmacyService pharmacyService;

CardlinkWebsocketClient cardlinkWebsocketClient;

IParser parser = FhirContext.forR4().newXmlParser();
public CETPServerHandler(PharmacyService pharmacyService, String cardLinkServer) {

public CETPServerHandler(PharmacyService pharmacyService, CardlinkWebsocketClient cardlinkWebsocketClient) {
this.pharmacyService = pharmacyService;
try {
log.info("Starting websocket connection to: "+cardLinkServer);
cardlinkWebsocketClient = new CardlinkWebsocketClient(new URI(cardLinkServer));
} catch (URISyntaxException e) {
log.log(Level.WARNING, "Could not connect to card link", e);
}
this.cardlinkWebsocketClient = cardlinkWebsocketClient;
}

@Override
public void handlerAdded(ChannelHandlerContext ctx) {
}

@Override
public void handlerRemoved(ChannelHandlerContext ctx) {
}

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
Event event = (Event) msg;

if(event.getTopic().equals("CARD/INSERTED")) {
if (event.getTopic().equals("CARD/INSERTED")) {
log.info("Card inserted");
String cardHandle = event.getMessage().getParameter().stream().filter(p -> p.getKey().equals("CardHandle")).map(p -> p.getValue()).findFirst().get();

int SlotID = Integer.parseInt(event.getMessage().getParameter().stream().filter(p -> p.getKey().equals("SlotID")).map(p -> p.getValue()).findFirst().get());
String CtID = event.getMessage().getParameter().stream().filter(p -> p.getKey().equals("CtID")).map(p -> p.getValue()).findFirst().get();
Integer slotId = Integer.parseInt(event.getMessage().getParameter().stream().filter(p -> p.getKey().equals("SlotID")).map(p -> p.getValue()).findFirst().get());
String ctId = event.getMessage().getParameter().stream().filter(p -> p.getKey().equals("CtID")).map(p -> p.getValue()).findFirst().get();

Long endTime = System.currentTimeMillis();
Pair<Bundle, String> pair;
try {
Bundle bundle = pharmacyService.getEPrescriptionsForCardHandle(cardHandle, null, null);
pair = pharmacyService.getEPrescriptionsForCardHandle(cardHandle, null, null);
Bundle bundle = pair.getKey();
String eventId = pair.getValue();
String xml = parser.encodeToString(bundle);
sendCardLinkMessage("eRezeptTokensFromAVS", Map.of("slotId", slotId, "ctId", ctId, "tokens", xml));

String payloadString = Json.createObjectBuilder().add("slotId", SlotID).add("ctID", CtID).add("tokens", xml).build().toString();

JsonObject j = Json.createObjectBuilder().add("type", "eRezeptTokensFromAVS").add("payload", DatatypeConverter.printBase64Binary(payloadString.getBytes())).build();
JsonArray jArray = Json.createArrayBuilder().add(j).build();
String jsonMessage = jArray.toString();
log.info(jsonMessage);
cardlinkWebsocketClient.sendMessage(jsonMessage);

JsonArrayBuilder bundles = Json.createArrayBuilder();
for(BundleEntryComponent entry : bundle.getEntry()) {
if(entry.getResource() instanceof org.hl7.fhir.r4.model.Task) {
/*
* <identifier>
* <use value="official"/>
* <system value="https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_PrescriptionId"/>
* <value value="160.000.187.347.039.26"/>
* </identifier>
* <identifier>
* <use value="official"/>
* <system value="https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_AccessCode"/>
* <value value="e624d3e6980e73d397517d0f2219aad553a11c9a8194fca04354eb346edbb266"/>
* </identifier>
*/

org.hl7.fhir.r4.model.Task task = (org.hl7.fhir.r4.model.Task) entry.getResource();
String taskId = task.getIdentifier().stream().filter(t -> "https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_PrescriptionId".equals(t.getSystem())).map(t -> t.getValue()).findAny().orElse(null);
String accessCode = task.getIdentifier().stream().filter(t -> "https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_AccessCode".equals(t.getSystem())).map(t -> t.getValue()).findAny().orElse(null);
log.info("TaskId: "+taskId+" AccessCode: "+accessCode);
String token = "/Task/"+taskId+"/$accept?ac="+accessCode;
try {
Bundle bundleEPrescription = pharmacyService.accept(token, new RuntimeConfig());
bundles.add(parser.encodeToString(bundleEPrescription));

} catch (Exception e) {
bundles.add("Error for "+token+" "+e.getMessage());
}
}
}
JsonArrayBuilder bundles = prepareBundles(bundle);
sendCardLinkMessage("eRezeptBundlesFromAVS", Map.of("slotId", slotId, "ctId", ctId, "bundles", bundles));

payloadString = Json.createObjectBuilder().add("slotId", SlotID).add("ctID", CtID).add("bundles", bundles).build().toString();
JsonObject eRezeptBundlesFromAVS = Json.createObjectBuilder().add("type", "eRezeptBundlesFromAVS").add("payload", DatatypeConverter.printBase64Binary(payloadString.getBytes())).build();
sendCardLinkMessage("vsdmSensorData", Map.of("slotId", slotId, "ctId", ctId, "endTime", endTime, "eventId", eventId));

jArray = Json.createArrayBuilder().add(eRezeptBundlesFromAVS).build();
log.info(jArray.toString());
cardlinkWebsocketClient.sendMessage(jArray.toString());

} catch (FaultMessage | de.gematik.ws.conn.eventservice.wsdl.v7.FaultMessage e) {
log.log(Level.WARNING, "Could not get prescription for Bundle", e);
String code = e instanceof FaultMessage
? ((FaultMessage) e).getFaultInfo().getTrace().get(0).getCode().toString()
: ((de.gematik.ws.conn.eventservice.wsdl.v7.FaultMessage) e).getFaultInfo().getTrace().get(0).getCode().toString();
sendCardLinkMessage("vsdmSensorData", Map.of("slotId", slotId, "ctId", ctId, "endTime", endTime, "err", code));
}
}

}

private JsonArrayBuilder prepareBundles(Bundle bundle) {
JsonArrayBuilder bundles = Json.createArrayBuilder();
for (BundleEntryComponent entry : bundle.getEntry()) {
if (entry.getResource() instanceof org.hl7.fhir.r4.model.Task) {
/*
* <identifier>
* <use value="official"/>
* <system value="https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_PrescriptionId"/>
* <value value="160.000.187.347.039.26"/>
* </identifier>
* <identifier>
* <use value="official"/>
* <system value="https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_AccessCode"/>
* <value value="e624d3e6980e73d397517d0f2219aad553a11c9a8194fca04354eb346edbb266"/>
* </identifier>
*/

org.hl7.fhir.r4.model.Task task = (org.hl7.fhir.r4.model.Task) entry.getResource();
String taskId = task.getIdentifier().stream().filter(t -> "https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_PrescriptionId".equals(t.getSystem())).map(t -> t.getValue()).findAny().orElse(null);
String accessCode = task.getIdentifier().stream().filter(t -> "https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_AccessCode".equals(t.getSystem())).map(t -> t.getValue()).findAny().orElse(null);
log.info("TaskId: " + taskId + " AccessCode: " + accessCode);
String token = "/Task/" + taskId + "/$accept?ac=" + accessCode;
try {
Bundle bundleEPrescription = pharmacyService.accept(token, new RuntimeConfig());
bundles.add(parser.encodeToString(bundleEPrescription));
} catch (Exception e) {
bundles.add("Error for " + token + " " + e.getMessage());
}
}
}
return bundles;
}

private void sendCardLinkMessage(String type, Map<String, ?> payloadMap) {
JsonObjectBuilder builder = Json.createObjectBuilder();
for (Map.Entry<String, ?> entry : payloadMap.entrySet()) {
if (entry.getValue() instanceof Integer) {
builder.add(entry.getKey(), (Integer) entry.getValue());
} else if (entry.getValue() instanceof Long) {
builder.add(entry.getKey(), (Long) entry.getValue());
} else if (entry.getValue() instanceof String) {
builder.add(entry.getKey(), (String) entry.getValue());
} else if (entry.getValue() instanceof JsonArrayBuilder) {
builder.add(entry.getKey(), (JsonArrayBuilder) entry.getValue());
}
}
String payload = builder.build().toString();
JsonObject jsonObject = Json.createObjectBuilder()
.add("type", type)
.add("payload", DatatypeConverter.printBase64Binary(payload.getBytes()))
.build();
JsonArray jsonArray = Json.createArrayBuilder().add(jsonObject).build();
cardlinkWebsocketClient.sendMessage(jsonArray.toString());
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
Expand Down
Loading
Loading