diff --git a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/_remote.repositories b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/_remote.repositories index a3a86373..7c1c5af6 100644 --- a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/_remote.repositories +++ b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/_remote.repositories @@ -1,5 +1,5 @@ #NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. -#Mon Oct 14 17:17:36 AMT 2024 +#Tue Oct 15 17:09:21 AMT 2024 lib-cetp-1.0-SNAPSHOT.jar>= lib-cetp-1.0-SNAPSHOT-sources.jar>= lib-cetp-1.0-SNAPSHOT.pom>= diff --git a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT-sources.jar b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT-sources.jar index 62dbf9ef..63efe989 100644 Binary files a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT-sources.jar and b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT-sources.jar differ diff --git a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT.jar b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT.jar index 14b02f3f..23a13130 100644 Binary files a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT.jar and b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT.jar differ diff --git a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT.pom b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT.pom index cef1c5d2..cc489154 100644 --- a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT.pom +++ b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/lib-cetp-1.0-SNAPSHOT.pom @@ -33,6 +33,12 @@ 3.0.1 provided + + jakarta.websocket + jakarta.websocket-client-api + 2.1.0 + provided + io.quarkus quarkus-scheduler-api diff --git a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/maven-metadata-local.xml b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/maven-metadata-local.xml index 0fab5ece..1b4456ab 100644 --- a/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/maven-metadata-local.xml +++ b/project-repo/de/servicehealth/lib-cetp/1.0-SNAPSHOT/maven-metadata-local.xml @@ -3,7 +3,7 @@ de.servicehealth lib-cetp - 20241014131730 + 20241015130915 true @@ -11,18 +11,18 @@ pom 1.0-SNAPSHOT - 20241014131730 + 20241015130915 jar 1.0-SNAPSHOT - 20241014131730 + 20241015130915 sources jar 1.0-SNAPSHOT - 20241014131730 + 20241015130915 diff --git a/project-repo/de/servicehealth/lib-cetp/maven-metadata-local.xml b/project-repo/de/servicehealth/lib-cetp/maven-metadata-local.xml index 6beb5058..04e511fc 100644 --- a/project-repo/de/servicehealth/lib-cetp/maven-metadata-local.xml +++ b/project-repo/de/servicehealth/lib-cetp/maven-metadata-local.xml @@ -6,6 +6,6 @@ 1.0-SNAPSHOT - 20241014131730 + 20241015130915 diff --git a/src/main/java/health/ere/ps/service/cardlink/AddJWTConfigurator.java b/src/main/java/health/ere/ps/service/cardlink/AddJWTConfigurator.java deleted file mode 100644 index 82cdbc81..00000000 --- a/src/main/java/health/ere/ps/service/cardlink/AddJWTConfigurator.java +++ /dev/null @@ -1,86 +0,0 @@ -package health.ere.ps.service.cardlink; - -import de.gematik.ws.conn.connectorcontext.v2.ContextType; -import de.gematik.ws.conn.eventservice.wsdl.v7.EventServicePortType; -import de.gematik.ws.conn.eventservice.wsdl.v7.FaultMessage; -import de.health.service.cetp.konnektorconfig.KonnektorConfig; -import health.ere.ps.config.RuntimeConfig; -import health.ere.ps.service.connector.provider.MultiConnectorServicesProvider; -import health.ere.ps.service.gematik.PharmacyService; -import io.quarkus.arc.Unremovable; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.websocket.ClientEndpointConfig; - -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static io.netty.handler.codec.http.HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL; - -@Unremovable -@ApplicationScoped -public class AddJWTConfigurator extends ClientEndpointConfig.Configurator { - - private static final Logger log = Logger.getLogger(AddJWTConfigurator.class.getName()); - - @Inject - PharmacyService pharmacyService; - - @Inject - MultiConnectorServicesProvider connectorServicesProvider; - - private static final Map configMap = new HashMap<>(); - - public static void initConfigs(Collection konnektorConfigs) { - konnektorConfigs.forEach(kc -> - configMap.put( - kc.getCardlinkEndpoint().getPath().replace("/websocket/", "").trim(), - new RuntimeConfig(kc.getUserConfigurations()) - ) - ); - } - - private boolean checkServicesAreValid() { - return pharmacyService != null && connectorServicesProvider != null; - } - - private RuntimeConfig buildRuntimeConfig(Map> headers) { - String serialNumber = null; - RuntimeConfig runtimeConfig = null; - - List wsProtocolHeaderValues = headers.get(SEC_WEBSOCKET_PROTOCOL.toString()); - if (!wsProtocolHeaderValues.isEmpty()) { - serialNumber = wsProtocolHeaderValues.get(0); - runtimeConfig = configMap.get(serialNumber); - } - if (runtimeConfig == null) { - log.warning(String.format("No KonnektorConfig is found for serialNumber=%s, using random config", serialNumber)); - runtimeConfig = new RuntimeConfig(); - } - return runtimeConfig; - } - - @Override - public void beforeRequest(Map> headers) { - if (checkServicesAreValid()) { - RuntimeConfig runtimeConfig = buildRuntimeConfig(headers); - headers.remove(SEC_WEBSOCKET_PROTOCOL.toString()); - ContextType context = connectorServicesProvider.getContextType(runtimeConfig); - EventServicePortType eventServicePortType = connectorServicesProvider.getEventServicePortType(runtimeConfig); - try { - pharmacyService.setAndGetSMCBHandleForPharmacy(runtimeConfig, context, eventServicePortType); - } catch (FaultMessage e) { - log.log(Level.SEVERE, "Could not get SMC-B for pharmacy", e); - } - String bearerToken = pharmacyService.getBearerTokenService().getBearerToken(runtimeConfig); - headers.put("Authorization", List.of("Bearer " + bearerToken)); - } else { - String msg = "Could not get pharmacyService or connectorServicesProvider, won't add JWT to websocket connection"; - log.log(Level.SEVERE, msg); - } - } -} diff --git a/src/main/java/health/ere/ps/service/cardlink/CardLinkEndpointConfig.java b/src/main/java/health/ere/ps/service/cardlink/CardLinkEndpointConfig.java deleted file mode 100644 index 062b37b4..00000000 --- a/src/main/java/health/ere/ps/service/cardlink/CardLinkEndpointConfig.java +++ /dev/null @@ -1,56 +0,0 @@ -package health.ere.ps.service.cardlink; - -import jakarta.websocket.ClientEndpointConfig; -import jakarta.websocket.Decoder; -import jakarta.websocket.Encoder; -import jakarta.websocket.Extension; - -import javax.net.ssl.SSLContext; -import java.util.List; -import java.util.Map; - -public class CardLinkEndpointConfig implements ClientEndpointConfig { - - private final Configurator configurator; - private final String serialNumber; - - public CardLinkEndpointConfig(Configurator configurator, String serialNumber) { - this.configurator = configurator; - this.serialNumber = serialNumber; - } - - @Override - public List getPreferredSubprotocols() { - return List.of(serialNumber); - } - - @Override - public List getExtensions() { - return List.of(); - } - - @Override - public SSLContext getSSLContext() { - return null; - } - - @Override - public Configurator getConfigurator() { - return configurator; - } - - @Override - public List> getEncoders() { - return List.of(); - } - - @Override - public List> getDecoders() { - return List.of(); - } - - @Override - public Map getUserProperties() { - return Map.of(); - } -} diff --git a/src/main/java/health/ere/ps/service/cardlink/CardlinkWebsocketClient.java b/src/main/java/health/ere/ps/service/cardlink/CardlinkWebsocketClient.java deleted file mode 100644 index bd841306..00000000 --- a/src/main/java/health/ere/ps/service/cardlink/CardlinkWebsocketClient.java +++ /dev/null @@ -1,169 +0,0 @@ -package health.ere.ps.service.cardlink; - -import java.io.IOException; -import java.net.URI; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import health.ere.ps.service.health.check.CardlinkWebsocketCheck; -import io.quarkus.arc.Arc; -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; -import jakarta.json.JsonObjectBuilder; -import jakarta.json.JsonValue; -import jakarta.websocket.ClientEndpoint; -import jakarta.websocket.CloseReason; -import jakarta.websocket.ContainerProvider; -import jakarta.websocket.DeploymentException; -import jakarta.websocket.Endpoint; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.OnClose; -import jakarta.websocket.OnMessage; -import jakarta.websocket.OnOpen; -import jakarta.websocket.Session; -import jakarta.websocket.WebSocketContainer; -import jakarta.xml.bind.DatatypeConverter; - -@SuppressWarnings("unused") -@ClientEndpoint(configurator = AddJWTConfigurator.class) -public class CardlinkWebsocketClient extends Endpoint { - - private static final Logger log = Logger.getLogger(CardlinkWebsocketClient.class.getName()); - - URI endpointURI; - Session userSession; - WebSocketContainer container; - - private CardlinkWebsocketCheck cardlinkWebsocketCheck; - - public CardlinkWebsocketClient() { - } - - public CardlinkWebsocketClient(URI endpointURI, CardlinkWebsocketCheck cardlinkWebsocketCheck) { - try { - this.cardlinkWebsocketCheck = cardlinkWebsocketCheck; - this.cardlinkWebsocketCheck.setConnected(false); - this.endpointURI = endpointURI; - container = ContainerProvider.getWebSocketContainer(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Callback hook for Connection open events. - * - * @param userSession the userSession which is opened. - */ - @OnOpen - @Override - public void onOpen(Session userSession, EndpointConfig config) { - log.info("opening websocket to " + endpointURI); - this.userSession = userSession; - cardlinkWebsocketCheck.setConnected(true); - } - - public void connect() { - try { - String serialNumber = endpointURI.getPath().replace("/websocket/", "").trim(); - AddJWTConfigurator jwtConfigurator = Arc.container().select(AddJWTConfigurator.class).get(); - CardLinkEndpointConfig endpointConfig = new CardLinkEndpointConfig(jwtConfigurator, serialNumber); - container.connectToServer(this, endpointConfig, endpointURI); - } catch (DeploymentException | IOException e) { - throw new RuntimeException(e); - } - } - - /** - * Callback hook for Connection close events. - * - * @param userSession the userSession which is getting closed. - * @param reason the reason for connection close - */ - @OnClose - public void onClose(Session userSession, CloseReason reason) { - log.info("closing websocket " + endpointURI); - cardlinkWebsocketCheck.setConnected(false); - } - - /** - * Callback hook for Message Events. This method will be invoked when a client send a message. - * - * @param message The text message - */ - @OnMessage - public void onMessage(String message) { - log.fine(message); - } - - public void sendJson(String correlationId, String iccsn, String type, Map payloadMap) { - JsonObjectBuilder objectBuilder = Json.createObjectBuilder().add("type", type); - if (!payloadMap.isEmpty()) { - JsonObjectBuilder builder = Json.createObjectBuilder(); - for (Map.Entry entry : payloadMap.entrySet()) { - if (entry.getValue() instanceof Integer intValue) { - builder.add(entry.getKey(), intValue); - } else if (entry.getValue() instanceof Long longValue) { - builder.add(entry.getKey(), longValue); - } else if (entry.getValue() instanceof String stringValue) { - if (stringValue.equalsIgnoreCase("null")) { - builder.add(entry.getKey(), JsonValue.NULL); - } else { - builder.add(entry.getKey(), stringValue); - } - } else if (entry.getValue() instanceof JsonArrayBuilder jsonArrayBuilderValue) { - builder.add(entry.getKey(), jsonArrayBuilderValue); - } - } - String payload = builder.build().toString(); - objectBuilder.add("payload", DatatypeConverter.printBase64Binary(payload.getBytes())); - } - JsonObject jsonObject = objectBuilder.build(); - JsonArrayBuilder jsonArrayBuilder = Json.createArrayBuilder() - .add(jsonObject) - .add(JsonValue.NULL) - .add(correlationId); - if (iccsn != null) { - jsonArrayBuilder.add(iccsn); - } - JsonArray jsonArray = jsonArrayBuilder.build(); - sendMessage(jsonArray.toString(), correlationId); - } - - /** - * Send a message. - * - * @param message String - */ - public void sendMessage(String message, String correlationId) { - try { - this.userSession.getBasicRemote().sendText(message); - log.fine(String.format("[%s] WS message is sent to cardlink: %s", correlationId, message)); - } catch (Throwable e) { - log.log(Level.WARNING, String.format("[%s] Could not send WS message to cardlink: %s", correlationId, message), e); - } - - // TODO - - /* - Jun 15 21:39:16 manuel-System-Product-Name promtail[275518]: level=error ts=2024-06-15T19:39:16.292577252Z - caller=client.go:430 component=client host=localhost:3100 msg="final error sending batch" status=400 - tenant= error="server returned HTTP status 400 Bad Request (400): stream ' - {err=\"[uuid] Could not send WS message to cardlink: [{\\\"type\\\":\\\"eRezeptTokensFromAVS\\\",\\\"payload\\\":\\\"eyJjdElkIjoiZTdhOGEwOTUtMTYxMy00YmZmLWE3MTQtMjEyYjcyYWRmZGFkIiwidG9rZW5zIjoiRVJST1I6IEZlaGxlciBiZWkgZGVyIEMyQy1BdXRoZW50aXNpZXJ1bmcgLT4gZGUuZ2VtYXRpay53cy5jb25uLnZzZHMudnNkc2VydmljZS52NS5GYXVsdE1lc3NhZ2U6IEZlaGxlciBiZWkgZGVyIEMyQy1BdXRoZW50aXNpZXJ1bmdcblx0YXQgamF2YS5iYXNlL2pkay5pbnRlcm5hbC5yZWZsZWN0LkRpcmVjdENvbnN0cnVjdG9ySGFuZGxlQWNjZXNzb3IubmV3SW5zdGFuY2UoRGlyZWN0Q29uc3RydWN0b3JIYW5kbGVBY2Nlc3Nvci5qYXZhOjYyKVxuXHRhdCBqYXZhLmJhc2UvamF2YS5sYW5nLnJlZmxlY3QuQ29uc3RydWN0b3IubmV3SW5zdGFuY2VXaXRoQ2FsbGVyKENvbnN0cnVjdG9yLmphdmE6NTAyKVxuXHRhdCBqYXZhLmJhc2UvamF2YS5sYW5nLnJlZmxlY3QuQ29uc3RydWN0b3IubmV3SW5zdGFuY2UoQ29uc3RydWN0b3IuamF2YTo0ODYpXG5cdGF0IGNvbS5zdW4ueG1sLndzLmZhdWx0LlNPQVBGYXVsdEJ1aWxkZXIuY3JlYXRlRXhjZXB0aW9uKFNPQVBGYXVsdEJ1aWxkZXIuamF2YToxMjMpXG5cdGF0IGNvbS5zdW4ueG1sLndzLmNsaWVudC5zZWkuU3R1YkhhbmRsZXIucmVhZFJlc3BvbnNlKFN0dWJIYW5kbGVyLmphdmE6MjI1KVxuXHRhdCBjb20uc3VuLnhtbC53cy5kYi5EYXRhYmluZGluZ0ltcG" - */ - } - - public void close() { - try { - // Close might be called even before @onOpen was called, hence userSession might be null. - if (this.userSession != null) { - userSession.close(); - } - } catch (IOException e) { - log.log(Level.WARNING, "Could not close websocket session", e); - } - } -} diff --git a/src/main/java/health/ere/ps/service/cardlink/EreJwtConfigurator.java b/src/main/java/health/ere/ps/service/cardlink/EreJwtConfigurator.java new file mode 100644 index 00000000..ea640d19 --- /dev/null +++ b/src/main/java/health/ere/ps/service/cardlink/EreJwtConfigurator.java @@ -0,0 +1,48 @@ +package health.ere.ps.service.cardlink; + +import de.health.service.cetp.IKonnektorClient; +import de.health.service.cetp.cardlink.JwtConfigurator; +import de.health.service.cetp.config.UserRuntimeConfig; +import de.health.service.cetp.domain.eventservice.card.Card; +import de.health.service.cetp.domain.eventservice.card.CardType; +import health.ere.ps.config.RuntimeConfig; +import health.ere.ps.service.idp.BearerTokenService; +import jakarta.validation.constraints.NotNull; + +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class EreJwtConfigurator extends JwtConfigurator { + + private static final Logger log = Logger.getLogger(EreJwtConfigurator.class.getName()); + private static final String NULL_WARNING = "Could not get pharmacyService or connectorServicesProvider, won't add JWT to websocket connection"; + + BearerTokenService bearerTokenService; + IKonnektorClient konnektorClient; + + public EreJwtConfigurator( + UserRuntimeConfig userRuntimeConfig, + @NotNull(message = NULL_WARNING) IKonnektorClient konnektorClient, + @NotNull(message = NULL_WARNING) BearerTokenService bearerTokenService + ) { + super(userRuntimeConfig); + this.konnektorClient = konnektorClient; + this.bearerTokenService = bearerTokenService; + } + + @Override + public void beforeRequest(Map> headers) { + RuntimeConfig runtimeConfig = (RuntimeConfig) userRuntimeConfig; + try { + List cards = konnektorClient.getCards(userRuntimeConfig, CardType.SMC_B); + String smcbHandle = cards.stream().map(Card::getCardHandle).findAny().orElse(null); + runtimeConfig.setSMCBHandle(smcbHandle); + } catch (Exception e) { + log.log(Level.SEVERE, "Could not get SMC-B for pharmacy", e); + } + String bearerToken = bearerTokenService.getBearerToken(runtimeConfig); + headers.put("Authorization", List.of("Bearer " + bearerToken)); + } +} diff --git a/src/main/java/health/ere/ps/service/cetp/CETPServerHandler.java b/src/main/java/health/ere/ps/service/cetp/CETPServerHandler.java index 9bbcdea8..1f261916 100644 --- a/src/main/java/health/ere/ps/service/cetp/CETPServerHandler.java +++ b/src/main/java/health/ere/ps/service/cetp/CETPServerHandler.java @@ -3,9 +3,9 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; import de.gematik.ws.conn.eventservice.v7.Event; +import de.health.service.cetp.cardlink.CardlinkWebsocketClient; import de.health.service.cetp.config.IUserConfigurations; import health.ere.ps.config.RuntimeConfig; -import health.ere.ps.service.cardlink.CardlinkWebsocketClient; import health.ere.ps.service.cetp.tracker.TrackerService; import health.ere.ps.service.gematik.PharmacyService; import io.netty.channel.ChannelHandlerContext; diff --git a/src/main/java/health/ere/ps/service/cetp/CETPServerHandlerFactory.java b/src/main/java/health/ere/ps/service/cetp/CETPServerHandlerFactory.java index 6a24dc6f..37ebd9d3 100644 --- a/src/main/java/health/ere/ps/service/cetp/CETPServerHandlerFactory.java +++ b/src/main/java/health/ere/ps/service/cetp/CETPServerHandlerFactory.java @@ -1,12 +1,16 @@ package health.ere.ps.service.cetp; import de.health.service.cetp.CETPEventHandlerFactory; +import de.health.service.cetp.IKonnektorClient; +import de.health.service.cetp.cardlink.CardlinkWebsocketClient; import de.health.service.cetp.konnektorconfig.KonnektorConfig; -import health.ere.ps.service.cardlink.CardlinkWebsocketClient; +import health.ere.ps.config.RuntimeConfig; +import health.ere.ps.service.cardlink.EreJwtConfigurator; import health.ere.ps.service.cetp.tracker.TrackerService; import health.ere.ps.service.common.security.SecretsManagerService; import health.ere.ps.service.gematik.PharmacyService; import health.ere.ps.service.health.check.CardlinkWebsocketCheck; +import health.ere.ps.service.idp.BearerTokenService; import io.netty.channel.ChannelInboundHandler; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -16,6 +20,8 @@ public class CETPServerHandlerFactory implements CETPEventHandlerFactory { TrackerService trackerService; PharmacyService pharmacyService; + IKonnektorClient konnektorClient; + BearerTokenService bearerTokenService; SecretsManagerService secretsManagerService; CardlinkWebsocketCheck cardlinkWebsocketCheck; @@ -23,20 +29,32 @@ public class CETPServerHandlerFactory implements CETPEventHandlerFactory { public CETPServerHandlerFactory( TrackerService trackerService, PharmacyService pharmacyService, + IKonnektorClient konnektorClient, + BearerTokenService bearerTokenService, SecretsManagerService secretsManagerService, CardlinkWebsocketCheck cardlinkWebsocketCheck ) { this.trackerService = trackerService; + this.konnektorClient = konnektorClient; this.pharmacyService = pharmacyService; - this.secretsManagerService = secretsManagerService; + this.bearerTokenService = bearerTokenService; this.cardlinkWebsocketCheck = cardlinkWebsocketCheck; + this.secretsManagerService = secretsManagerService; } @Override - public ChannelInboundHandler build(KonnektorConfig konnektorConfig) { + public ChannelInboundHandler build(KonnektorConfig kc) { CardlinkWebsocketClient cardlinkWebsocketClient = new CardlinkWebsocketClient( - konnektorConfig.getCardlinkEndpoint(), - cardlinkWebsocketCheck + kc.getCardlinkEndpoint(), + new EreJwtConfigurator( + new RuntimeConfig(kc.getUserConfigurations()), + konnektorClient, + bearerTokenService + ) + ); + cardlinkWebsocketCheck.register( + kc.getCardlinkEndpoint(), + cardlinkWebsocketClient.connected() ); return new CETPServerHandler(trackerService, pharmacyService, cardlinkWebsocketClient); } diff --git a/src/main/java/health/ere/ps/service/cetp/KonnektorClient.java b/src/main/java/health/ere/ps/service/cetp/KonnektorClient.java index ef09f607..a35f20e4 100644 --- a/src/main/java/health/ere/ps/service/cetp/KonnektorClient.java +++ b/src/main/java/health/ere/ps/service/cetp/KonnektorClient.java @@ -2,6 +2,7 @@ import de.gematik.ws.conn.connectorcommon.v5.Status; import de.gematik.ws.conn.connectorcontext.v2.ContextType; +import de.gematik.ws.conn.eventservice.v7.GetCards; import de.gematik.ws.conn.eventservice.v7.GetSubscription; import de.gematik.ws.conn.eventservice.v7.GetSubscriptionResponse; import de.gematik.ws.conn.eventservice.v7.RenewSubscriptionsResponse; @@ -14,10 +15,15 @@ import de.health.service.cetp.domain.CetpStatus; import de.health.service.cetp.domain.SubscriptionResult; import de.health.service.cetp.domain.eventservice.Subscription; +import de.health.service.cetp.domain.eventservice.card.Card; +import de.health.service.cetp.domain.eventservice.card.CardType; +import de.health.service.cetp.domain.eventservice.card.CardsResponse; import de.health.service.cetp.domain.fault.CetpFault; -import health.ere.ps.service.cetp.mapper.StatusMapper; -import health.ere.ps.service.cetp.mapper.SubscriptionMapper; -import health.ere.ps.service.cetp.mapper.SubscriptionResultMapper; +import health.ere.ps.service.cetp.mapper.card.CardTypeMapper; +import health.ere.ps.service.cetp.mapper.card.CardsResponseMapper; +import health.ere.ps.service.cetp.mapper.status.StatusMapper; +import health.ere.ps.service.cetp.mapper.subscription.SubscriptionMapper; +import health.ere.ps.service.cetp.mapper.subscription.SubscriptionResultMapper; import health.ere.ps.service.connector.provider.MultiConnectorServicesProvider; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -43,6 +49,12 @@ public class KonnektorClient implements IKonnektorClient { @Inject SubscriptionMapper subscriptionMapper; + @Inject + CardsResponseMapper cardsResponseMapper; + + @Inject + CardTypeMapper cardTypeMapper; + @Inject StatusMapper statusMapper; @@ -124,4 +136,19 @@ public CetpStatus unsubscribe( throw new CetpFault(faultMessage.getMessage()); } } + + @Override + public List getCards(UserRuntimeConfig runtimeConfig, CardType cardType) throws CetpFault { + ContextType context = connectorServicesProvider.getContextType(runtimeConfig); + EventServicePortType eventService = connectorServicesProvider.getEventServicePortType(runtimeConfig); + GetCards parameter = new GetCards(); + parameter.setContext(context); + parameter.setCardType(cardTypeMapper.toSoap(cardType)); + try { + CardsResponse cardsResponse = cardsResponseMapper.toDomain(eventService.getCards(parameter)); + return cardsResponse.getCards(); + } catch (FaultMessage faultMessage) { + throw new CetpFault(faultMessage.getMessage()); + } + } } diff --git a/src/main/java/health/ere/ps/service/cetp/RegisterSMCBJob.java b/src/main/java/health/ere/ps/service/cetp/RegisterSMCBJob.java index 7feb9255..f88ed7dd 100644 --- a/src/main/java/health/ere/ps/service/cetp/RegisterSMCBJob.java +++ b/src/main/java/health/ere/ps/service/cetp/RegisterSMCBJob.java @@ -1,21 +1,13 @@ package health.ere.ps.service.cetp; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - import de.health.service.cetp.SubscriptionManager; +import de.health.service.cetp.cardlink.CardlinkWebsocketClient; import de.health.service.cetp.konnektorconfig.KonnektorConfig; +import health.ere.ps.config.RuntimeConfig; import health.ere.ps.jmx.SubscriptionsMXBean; import health.ere.ps.jmx.SubscriptionsMXBeanImpl; -import health.ere.ps.service.cardlink.AddJWTConfigurator; -import health.ere.ps.service.cardlink.CardlinkWebsocketClient; -import health.ere.ps.service.health.check.CardlinkWebsocketCheck; +import health.ere.ps.service.cardlink.EreJwtConfigurator; +import health.ere.ps.service.idp.BearerTokenService; import io.quarkus.runtime.StartupEvent; import io.quarkus.scheduler.Scheduled; import jakarta.annotation.Priority; @@ -23,6 +15,15 @@ import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + import static health.ere.ps.jmx.PsMXBeanManager.registerMXBean; @ApplicationScoped @@ -31,14 +32,17 @@ public class RegisterSMCBJob { private final static Logger log = Logger.getLogger(RegisterSMCBJob.class.getName()); @Inject - CardlinkWebsocketCheck cardlinkWebsocketCheck; + KonnektorClient konnektorClient; + + @Inject + BearerTokenService bearerTokenService; @Inject SubscriptionManager subscriptionManager; private List cardlinkWebsocketClients = new ArrayList<>(); - // Make sure subscription manager get's onStart first, before RegisterSMCBJob at least! + // Make sure subscription manager calls onStart first, before RegisterSMCBJob at least! void onStart(@Observes @Priority(5300) StartupEvent ev) { log.info("RegisterSMCBJob init onStart"); initWSClients(); @@ -52,11 +56,17 @@ private void initWSClients() { cardlinkWebsocketClients = new ArrayList<>(); konnektorConfigs.forEach(kc -> - cardlinkWebsocketClients.add(new CardlinkWebsocketClient( - kc.getCardlinkEndpoint(), - cardlinkWebsocketCheck) - )); - AddJWTConfigurator.initConfigs(konnektorConfigs); + cardlinkWebsocketClients.add( + new CardlinkWebsocketClient( + kc.getCardlinkEndpoint(), + new EreJwtConfigurator( + new RuntimeConfig(kc.getUserConfigurations()), + konnektorClient, + bearerTokenService + ) + ) + ) + ); } @Scheduled( @@ -67,14 +77,14 @@ private void initWSClients() { void registerSmcbMaintenance() { String correlationId = UUID.randomUUID().toString(); log.info(String.format("RegisterSMCBJob started with %s", correlationId)); - // reload cardlink configs if neccessary - if(cardlinkWebsocketClients.isEmpty()) { + // reload cardlink configs if necessary + if (cardlinkWebsocketClients.isEmpty()) { initWSClients(); } cardlinkWebsocketClients.forEach(client -> { try { client.connect(); - client.sendJson(correlationId, null,"registerSMCB", Map.of()); + client.sendJson(correlationId, null, "registerSMCB", Map.of()); } catch (Exception e) { log.log(Level.SEVERE, "Error while sending registerSMCB", e); } finally { diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/card/CardMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/card/CardMapper.java new file mode 100644 index 00000000..5f6c8c41 --- /dev/null +++ b/src/main/java/health/ere/ps/service/cetp/mapper/card/CardMapper.java @@ -0,0 +1,12 @@ +package health.ere.ps.service.cetp.mapper.card; + +import de.gematik.ws.conn.cardservice.v8.CardInfoType; +import de.health.service.cetp.domain.eventservice.card.Card; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; +import org.mapstruct.Mapper; + +@Mapper(config = DefaultMappingConfig.class, uses = {CardTypeMapper.class, CardVersionMapper.class}) +public interface CardMapper { + + Card toDomain(CardInfoType soap); +} diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/card/CardTypeMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/card/CardTypeMapper.java new file mode 100644 index 00000000..1f1daa86 --- /dev/null +++ b/src/main/java/health/ere/ps/service/cetp/mapper/card/CardTypeMapper.java @@ -0,0 +1,14 @@ +package health.ere.ps.service.cetp.mapper.card; + +import de.gematik.ws.conn.cardservicecommon.v2.CardTypeType; +import de.health.service.cetp.domain.eventservice.card.CardType; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; +import org.mapstruct.Mapper; + +@Mapper(config = DefaultMappingConfig.class) +public interface CardTypeMapper { + + CardTypeType toSoap(CardType domain); + + CardType toDomain(CardTypeType soap); +} diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/card/CardVersionMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/card/CardVersionMapper.java new file mode 100644 index 00000000..de990f5c --- /dev/null +++ b/src/main/java/health/ere/ps/service/cetp/mapper/card/CardVersionMapper.java @@ -0,0 +1,15 @@ +package health.ere.ps.service.cetp.mapper.card; + +import de.health.service.cetp.domain.eventservice.card.CardVersion; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = DefaultMappingConfig.class, uses = {VersionMapper.class}) +public interface CardVersionMapper { + + @Mapping(target = "cosVersion", source = "COSVersion") + @Mapping(target = "atrVersion", source = "ATRVersion") + @Mapping(target = "gdoVersion", source = "GDOVersion") + CardVersion toDomain(de.gematik.ws.conn.cardservice.v8.CardInfoType.CardVersion soap); +} diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/card/CardsResponseMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/card/CardsResponseMapper.java new file mode 100644 index 00000000..5be467a6 --- /dev/null +++ b/src/main/java/health/ere/ps/service/cetp/mapper/card/CardsResponseMapper.java @@ -0,0 +1,15 @@ +package health.ere.ps.service.cetp.mapper.card; + +import de.gematik.ws.conn.eventservice.v7.GetCardsResponse; +import de.health.service.cetp.domain.eventservice.card.CardsResponse; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; +import health.ere.ps.service.cetp.mapper.status.StatusMapper; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = DefaultMappingConfig.class, uses = {CardMapper.class, StatusMapper.class}) +public interface CardsResponseMapper { + + @Mapping(target = "cards", source = "cards.card") + CardsResponse toDomain(GetCardsResponse soap); +} diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/card/VersionMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/card/VersionMapper.java new file mode 100644 index 00000000..de612403 --- /dev/null +++ b/src/main/java/health/ere/ps/service/cetp/mapper/card/VersionMapper.java @@ -0,0 +1,12 @@ +package health.ere.ps.service.cetp.mapper.card; + +import de.gematik.ws.conn.cardservice.v8.VersionInfoType; +import de.health.service.cetp.domain.eventservice.card.VersionInfo; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; +import org.mapstruct.Mapper; + +@Mapper(config = DefaultMappingConfig.class) +public interface VersionMapper { + + VersionInfo toDomain(VersionInfoType soap); +} diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/DetailMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/status/DetailMapper.java similarity index 67% rename from src/main/java/health/ere/ps/service/cetp/mapper/DetailMapper.java rename to src/main/java/health/ere/ps/service/cetp/mapper/status/DetailMapper.java index 32a29b6c..2f13f5bc 100644 --- a/src/main/java/health/ere/ps/service/cetp/mapper/DetailMapper.java +++ b/src/main/java/health/ere/ps/service/cetp/mapper/status/DetailMapper.java @@ -1,6 +1,7 @@ -package health.ere.ps.service.cetp.mapper; +package health.ere.ps.service.cetp.mapper.status; import de.health.service.cetp.domain.fault.Detail; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; import org.mapstruct.Mapper; @Mapper(config = DefaultMappingConfig.class) diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/ErrorMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/status/ErrorMapper.java similarity index 74% rename from src/main/java/health/ere/ps/service/cetp/mapper/ErrorMapper.java rename to src/main/java/health/ere/ps/service/cetp/mapper/status/ErrorMapper.java index cddd0025..bbed5628 100644 --- a/src/main/java/health/ere/ps/service/cetp/mapper/ErrorMapper.java +++ b/src/main/java/health/ere/ps/service/cetp/mapper/status/ErrorMapper.java @@ -1,6 +1,7 @@ -package health.ere.ps.service.cetp.mapper; +package health.ere.ps.service.cetp.mapper.status; import de.health.service.cetp.domain.fault.Error; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; import org.mapstruct.Mapper; import org.mapstruct.Mapping; diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/StatusMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/status/StatusMapper.java similarity index 71% rename from src/main/java/health/ere/ps/service/cetp/mapper/StatusMapper.java rename to src/main/java/health/ere/ps/service/cetp/mapper/status/StatusMapper.java index fc3c272e..b2201c3f 100644 --- a/src/main/java/health/ere/ps/service/cetp/mapper/StatusMapper.java +++ b/src/main/java/health/ere/ps/service/cetp/mapper/status/StatusMapper.java @@ -1,7 +1,8 @@ -package health.ere.ps.service.cetp.mapper; +package health.ere.ps.service.cetp.mapper.status; import de.gematik.ws.conn.connectorcommon.v5.Status; import de.health.service.cetp.domain.CetpStatus; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; import org.mapstruct.Mapper; @Mapper(config = DefaultMappingConfig.class, uses = {ErrorMapper.class}) diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/TraceMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/status/TraceMapper.java similarity index 74% rename from src/main/java/health/ere/ps/service/cetp/mapper/TraceMapper.java rename to src/main/java/health/ere/ps/service/cetp/mapper/status/TraceMapper.java index 09a802c0..efe2e7d1 100644 --- a/src/main/java/health/ere/ps/service/cetp/mapper/TraceMapper.java +++ b/src/main/java/health/ere/ps/service/cetp/mapper/status/TraceMapper.java @@ -1,6 +1,7 @@ -package health.ere.ps.service.cetp.mapper; +package health.ere.ps.service.cetp.mapper.status; import de.health.service.cetp.domain.fault.Trace; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; import org.mapstruct.Mapper; import org.mapstruct.Mapping; diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/subscription/SubscriptionMapper.java similarity index 75% rename from src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionMapper.java rename to src/main/java/health/ere/ps/service/cetp/mapper/subscription/SubscriptionMapper.java index 602891a5..7abc8ea7 100644 --- a/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionMapper.java +++ b/src/main/java/health/ere/ps/service/cetp/mapper/subscription/SubscriptionMapper.java @@ -1,6 +1,7 @@ -package health.ere.ps.service.cetp.mapper; +package health.ere.ps.service.cetp.mapper.subscription; import de.health.service.cetp.domain.eventservice.Subscription; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; import org.mapstruct.Mapper; import org.mapstruct.Mapping; diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionResultMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/subscription/SubscriptionResultMapper.java similarity index 89% rename from src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionResultMapper.java rename to src/main/java/health/ere/ps/service/cetp/mapper/subscription/SubscriptionResultMapper.java index f2e4bf15..724eb5e0 100644 --- a/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionResultMapper.java +++ b/src/main/java/health/ere/ps/service/cetp/mapper/subscription/SubscriptionResultMapper.java @@ -1,9 +1,12 @@ -package health.ere.ps.service.cetp.mapper; +package health.ere.ps.service.cetp.mapper.subscription; import de.gematik.ws.conn.connectorcommon.v5.Status; import de.gematik.ws.conn.eventservice.v7.SubscriptionRenewal; import de.health.service.cetp.domain.CetpStatus; import de.health.service.cetp.domain.SubscriptionResult; +import health.ere.ps.service.cetp.mapper.DefaultMappingConfig; +import health.ere.ps.service.cetp.mapper.status.StatusMapper; +import health.ere.ps.service.cetp.mapper.status.StatusMapperImpl; import jakarta.xml.ws.Holder; import org.mapstruct.AfterMapping; import org.mapstruct.Context; diff --git a/src/main/java/health/ere/ps/service/gematik/PharmacyService.java b/src/main/java/health/ere/ps/service/gematik/PharmacyService.java index b4bc7342..7396c15c 100644 --- a/src/main/java/health/ere/ps/service/gematik/PharmacyService.java +++ b/src/main/java/health/ere/ps/service/gematik/PharmacyService.java @@ -69,8 +69,6 @@ import java.util.stream.Stream; import java.util.zip.GZIPInputStream; -import static com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_SELF_REFERENCES; - /* Note: reading, writing and resending of failed rejects are done by one Thread (see scheduledExecutorService), no additional synchronization for retrying reject is need */ @ApplicationScoped public class PharmacyService implements AutoCloseable { @@ -395,8 +393,4 @@ public boolean attemptReject(String prescriptionId, String secret, RuntimeConfig public void setReadEPrescriptionsMXBean(ReadEPrescriptionsMXBeanImpl readEPrescriptionsMXBean) { this.readEPrescriptionsMXBean = readEPrescriptionsMXBean; } - - public BearerTokenService getBearerTokenService() { - return bearerTokenService; - } } diff --git a/src/main/java/health/ere/ps/service/health/HealthChecker.java b/src/main/java/health/ere/ps/service/health/HealthChecker.java index bd2810b2..fd412b51 100644 --- a/src/main/java/health/ere/ps/service/health/HealthChecker.java +++ b/src/main/java/health/ere/ps/service/health/HealthChecker.java @@ -22,7 +22,7 @@ public HealthInfo getHealthInfo(RuntimeConfig runtimeConfig) { boolean anyChecks500 = checks.stream() .map(check -> check.getSafeStatus(runtimeConfig)) .anyMatch(status -> status.equals(Status.Down500)); - + return new HealthInfo( anyChecks500 ? "DOWN" : "UP", checks.stream().map(check -> { diff --git a/src/main/java/health/ere/ps/service/health/check/CardlinkWebsocketCheck.java b/src/main/java/health/ere/ps/service/health/check/CardlinkWebsocketCheck.java index 8672b715..5ed99525 100644 --- a/src/main/java/health/ere/ps/service/health/check/CardlinkWebsocketCheck.java +++ b/src/main/java/health/ere/ps/service/health/check/CardlinkWebsocketCheck.java @@ -2,17 +2,20 @@ import health.ere.ps.config.RuntimeConfig; import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.context.Dependent; +import java.net.URI; +import java.util.HashMap; import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Collectors; -@Dependent +@ApplicationScoped public class CardlinkWebsocketCheck implements Check { - private boolean connected; + private final Map> wsConnections = new HashMap<>(); - public void setConnected(boolean connected) { - this.connected = connected; + public void register(URI uri, Supplier connected) { + wsConnections.put(uri, connected); } @Override @@ -22,11 +25,16 @@ public String getName() { @Override public Status getStatus(RuntimeConfig runtimeConfig) { - return connected ? Status.Up200 : Status.Down503; + return wsConnections.values().stream().allMatch(Supplier::get) ? Status.Up200 : Status.Down503; } @Override public Map getData(RuntimeConfig runtimeConfig) { - return Map.of("CardlinkWebsocket", connected ? "CONNECTED" : "DISCONNECTED"); + return wsConnections.entrySet().stream().collect( + Collectors.toMap( + e -> String.format("CardlinkWebsocket -> %s", e.getKey()), + e -> e.getValue().get() ? "CONNECTED" : "DISCONNECTED" + ) + ); } } diff --git a/src/test/java/health/ere/ps/service/gematik/CardInsertedTest.java b/src/test/java/health/ere/ps/service/gematik/CardInsertedTest.java index c27678b2..184e10c4 100644 --- a/src/test/java/health/ere/ps/service/gematik/CardInsertedTest.java +++ b/src/test/java/health/ere/ps/service/gematik/CardInsertedTest.java @@ -3,10 +3,10 @@ import de.gematik.ws.conn.eventservice.v7.Event; import de.gematik.ws.conn.vsds.vsdservice.v5.FaultMessage; import de.gematik.ws.tel.error.v2.Error; +import de.health.service.cetp.cardlink.CardlinkWebsocketClient; import health.ere.ps.config.AppConfig; import health.ere.ps.jmx.ReadEPrescriptionsMXBeanImpl; import health.ere.ps.model.config.UserConfigurations; -import health.ere.ps.service.cardlink.CardlinkWebsocketClient; import health.ere.ps.service.cetp.CETPServerHandler; import health.ere.ps.service.cetp.tracker.TrackerService; import health.ere.ps.service.idp.BearerTokenService; diff --git a/src/test/java/health/ere/ps/service/health/HealthCheckTest.java b/src/test/java/health/ere/ps/service/health/HealthCheckTest.java index 2fc18f8d..443d543e 100644 --- a/src/test/java/health/ere/ps/service/health/HealthCheckTest.java +++ b/src/test/java/health/ere/ps/service/health/HealthCheckTest.java @@ -3,6 +3,7 @@ import de.gematik.ws.conn.certificateservice.wsdl.v6.CertificateServicePortType; import de.gematik.ws.conn.connectorcontext.v2.ContextType; import de.gematik.ws.conn.eventservice.wsdl.v7.EventServicePortType; +import de.health.service.cetp.CETPServer; import health.ere.ps.profile.RUDevTestProfile; import health.ere.ps.service.connector.provider.MultiConnectorServicesProvider; import health.ere.ps.service.idp.BearerTokenService; @@ -19,6 +20,17 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.FileInputStream; +import java.io.OutputStream; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; import java.util.Optional; import static health.ere.ps.service.health.check.Check.CARDLINK_WEBSOCKET_CHECK; @@ -65,36 +77,74 @@ void afterAll() { } @Test - void healthCheckWorks() { + void healthCheckWorks() throws Exception { RestAssuredConfig config = RestAssured.config() - .httpClient(HttpClientConfig.httpClientConfig() - .setParam(CONNECTION_TIMEOUT, 10000) - .setParam(SO_TIMEOUT, 10000)); + .httpClient(HttpClientConfig.httpClientConfig() + .setParam(CONNECTION_TIMEOUT, 10000) + .setParam(SO_TIMEOUT, 10000)); + + connectToCetpServer(); Response response = given().header(new Header("X-eHBAHandle", "test")).config(config).when().get("/health"); response.then().statusCode(200); HealthInfo healthInfo = response.getBody().as(HealthInfo.class); assertThat(healthInfo.checks().size(), equalTo(3)); Optional cardLinkWebsocketCheckOpt = healthInfo.checks() - .stream() - .filter(check -> check.name().equals(CARDLINK_WEBSOCKET_CHECK)) - .findFirst(); + .stream() + .filter(check -> check.name().equals(CARDLINK_WEBSOCKET_CHECK)) + .findFirst(); assertTrue(cardLinkWebsocketCheckOpt.isPresent()); assertThat(cardLinkWebsocketCheckOpt.get().status(), equalTo("DOWN")); Optional cetpServerCheckOpt = healthInfo.checks() - .stream() - .filter(check -> check.name().equals(CETP_SERVER_CHECK)) - .findFirst(); + .stream() + .filter(check -> check.name().equals(CETP_SERVER_CHECK)) + .findFirst(); assertTrue(cetpServerCheckOpt.isPresent()); assertThat(cetpServerCheckOpt.get().status(), equalTo("UP")); assertThat(cetpServerCheckOpt.get().data().size(), equalTo(3)); Optional statusCheckOpt = healthInfo.checks() - .stream() - .filter(check -> check.name().equals(STATUS_CHECK)) - .findFirst(); + .stream() + .filter(check -> check.name().equals(STATUS_CHECK)) + .findFirst(); assertTrue(statusCheckOpt.isPresent()); assertThat(statusCheckOpt.get().status(), equalTo("DOWN")); } + + private void connectToCetpServer() throws Exception { + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, new TrustManager[]{new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) { + } + + public void checkServerTrusted(X509Certificate[] certs, String authType) { + } + }}, new SecureRandom()); + SSLSocketFactory sslsocketfactory = sc.getSocketFactory(); + + SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", CETPServer.DEFAULT_PORT); + try { + sslsocket.startHandshake(); + + try (OutputStream outputstream = new BufferedOutputStream(sslsocket.getOutputStream()); + FileInputStream in = new FileInputStream("src/test/resources/cetp/CARD_INSERTED.xml")) { + byte[] event = in.readAllBytes(); + byte[] cetpHeader = new byte[]{'C', 'E', 'T', 'P'}; + outputstream.write(cetpHeader); + new DataOutputStream(outputstream).writeInt(event.length); + outputstream.write(event); + outputstream.flush(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + sslsocket.close(); + } + + } }