diff --git a/pom.xml b/pom.xml
index a5210f386..ae21e66e2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,18 +10,18 @@
3.8.1
true
- 17
- 17
UTF-8
UTF-8
+
3.9.4
quarkus-universe-bom
io.quarkus
3.9.4
- 3.2.5
- 3.0.0-M5
7.4.0
2.5.1
+
+ 3.2.5
+ 3.5.0
@@ -203,6 +203,16 @@
Saxon-HE
10.3
+
+ de.servicehealth.libcetp
+ lib-cetp
+ 1.0-SNAPSHOT
+
+
+ org.mapstruct
+ mapstruct
+ 1.6.2
+
health.ere
api-telematik-service
@@ -387,10 +397,6 @@
-
- maven-compiler-plugin
- ${compiler-plugin.version}
-
maven-surefire-plugin
${surefire-plugin.version}
@@ -400,10 +406,25 @@
dev
org.jboss.logmanager.LogManager
INFO
- ${maven.home}
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${compiler-plugin.version}
+
+
+ 17
+
+
+ org.mapstruct
+ mapstruct-processor
+ 1.6.2
+
+
+
+
com.github.spotbugs
@@ -461,8 +482,9 @@
+ org.apache.maven.plugins
maven-failsafe-plugin
- ${surefire-plugin.version}
+ ${failsafe-plugin.version}
@@ -472,12 +494,8 @@
dev
-
- ${project.build.directory}/${project.build.finalName}-runner
-
- org.jboss.logmanager.LogManager
-
- ${maven.home}
+ ${project.build.directory}/${project.build.finalName}-runner
+ org.jboss.logmanager.LogManager
diff --git a/src/main/java/health/ere/ps/config/AppConfig.java b/src/main/java/health/ere/ps/config/AppConfig.java
index cd892d1fd..7bfad8905 100644
--- a/src/main/java/health/ere/ps/config/AppConfig.java
+++ b/src/main/java/health/ere/ps/config/AppConfig.java
@@ -1,6 +1,7 @@
package health.ere.ps.config;
-import health.ere.ps.service.cetp.CETPServer;
+import de.health.service.cetp.CETPServer;
+import de.health.service.cetp.config.SubscriptionConfig;
import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -13,8 +14,9 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+@SuppressWarnings({"LombokGetterMayBeUsed", "LombokSetterMayBeUsed"})
@ApplicationScoped
-public class AppConfig {
+public class AppConfig implements SubscriptionConfig {
private static final Logger log = Logger.getLogger(AppConfig.class.getName());
@@ -194,8 +196,8 @@ public String getKonnectorHost() {
return konnectorHost;
}
- public Integer getCetpPort() {
- return cetpPort.orElse(CETPServer.PORT);
+ public int getCetpPort() {
+ return cetpPort.orElse(CETPServer.DEFAULT_PORT);
}
public String getConnectorCrypt() {
diff --git a/src/main/java/health/ere/ps/config/RuntimeConfig.java b/src/main/java/health/ere/ps/config/RuntimeConfig.java
index 499503569..4593f08ae 100644
--- a/src/main/java/health/ere/ps/config/RuntimeConfig.java
+++ b/src/main/java/health/ere/ps/config/RuntimeConfig.java
@@ -7,6 +7,8 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import de.health.service.cetp.config.IRuntimeConfig;
+import de.health.service.cetp.config.IUserConfigurations;
import health.ere.ps.model.config.UserConfigurations;
import jakarta.enterprise.inject.Alternative;
import jakarta.enterprise.inject.spi.CDI;
@@ -14,7 +16,7 @@
import jakarta.servlet.http.HttpServletRequest;
@Alternative
-public class RuntimeConfig extends UserConfig {
+public class RuntimeConfig extends UserConfig implements IRuntimeConfig {
private static Logger log = Logger.getLogger(RuntimeConfig.class.getName());
@@ -39,7 +41,7 @@ public RuntimeConfig() {
}
}
- public RuntimeConfig(UserConfigurations userConfigurations) {
+ public RuntimeConfig(IUserConfigurations userConfigurations) {
this();
this.updateProperties(userConfigurations);
}
diff --git a/src/main/java/health/ere/ps/config/SimpleUserConfig.java b/src/main/java/health/ere/ps/config/SimpleUserConfig.java
index 022da16bf..e7037607e 100644
--- a/src/main/java/health/ere/ps/config/SimpleUserConfig.java
+++ b/src/main/java/health/ere/ps/config/SimpleUserConfig.java
@@ -1,5 +1,9 @@
package health.ere.ps.config;
+import de.health.service.cetp.config.IRuntimeConfig;
+import de.health.service.cetp.config.IUserConfigurations;
+import de.health.service.cetp.config.UserRuntimeConfig;
+
import java.util.Objects;
public class SimpleUserConfig {
@@ -52,7 +56,7 @@ public class SimpleUserConfig {
- public SimpleUserConfig(UserConfig userConfig) {
+ public SimpleUserConfig(UserRuntimeConfig userConfig) {
setValues(userConfig);
}
@@ -210,25 +214,28 @@ public void setIdpClientId(String idpClientId) {
this.idpClientId = idpClientId;
}
- private void setValues(UserConfig userConfig) {
- this.erixaHotfolder = userConfig.getConfigurations().getErixaHotfolder();
- this.erixaDrugstoreEmail = userConfig.getConfigurations().getErixaDrugstoreEmail();
- this.erixaUserEmail = userConfig.getConfigurations().getErixaUserEmail();
- this.erixaApiKey = userConfig.getConfigurations().getErixaApiKey();
- this.muster16TemplateProfile = userConfig.getConfigurations().getMuster16TemplateProfile();
- this.connectorBaseURL = userConfig.getConfigurations().getConnectorBaseURL();
- this.mandantId = userConfig.getConfigurations().getMandantId();
- this.workplaceId = userConfig.getConfigurations().getWorkplaceId();
- this.clientSystemId = userConfig.getConfigurations().getClientSystemId();
- this.userId = userConfig.getConfigurations().getUserId();
- this.version = userConfig.getConfigurations().getVersion();
- this.tvMode = userConfig.getConfigurations().getTvMode();
- if(userConfig.getClass().getName().contains("RuntimeConfig")) {
- this.eHBAHandle = ((RuntimeConfig)userConfig).getEHBAHandle();
- this.SMCBHandle = ((RuntimeConfig)userConfig).getSMCBHandle();
- this.sendPreview = ((RuntimeConfig)userConfig).isSendPreview();
- this.idpAuthRequestRedirectURL = ((RuntimeConfig)userConfig).getIdpAuthRequestRedirectURL();
- this.idpClientId = ((RuntimeConfig)userConfig).getIdpClientId();
+ private void setValues(UserRuntimeConfig userConfig) {
+ IUserConfigurations configurations = userConfig.getUserConfigurations();
+ this.erixaHotfolder = configurations.getErixaHotfolder();
+ this.erixaDrugstoreEmail = configurations.getErixaDrugstoreEmail();
+ this.erixaUserEmail = configurations.getErixaUserEmail();
+ this.erixaApiKey = configurations.getErixaApiKey();
+ this.muster16TemplateProfile = configurations.getMuster16TemplateProfile();
+ this.connectorBaseURL = configurations.getConnectorBaseURL();
+ this.mandantId = configurations.getMandantId();
+ this.workplaceId = configurations.getWorkplaceId();
+ this.clientSystemId = configurations.getClientSystemId();
+ this.userId = configurations.getUserId();
+ this.version = configurations.getVersion();
+ this.tvMode = configurations.getTvMode();
+
+ IRuntimeConfig runtimeConfig = userConfig.getRuntimeConfig();
+ if (runtimeConfig != null) {
+ this.eHBAHandle = runtimeConfig.getEHBAHandle();
+ this.SMCBHandle = runtimeConfig.getSMCBHandle();
+ this.sendPreview = runtimeConfig.isSendPreview();
+ this.idpAuthRequestRedirectURL = runtimeConfig.getIdpAuthRequestRedirectURL();
+ this.idpClientId = runtimeConfig.getIdpClientId();
}
}
diff --git a/src/main/java/health/ere/ps/config/UserConfig.java b/src/main/java/health/ere/ps/config/UserConfig.java
index fc67d100c..a036606ac 100644
--- a/src/main/java/health/ere/ps/config/UserConfig.java
+++ b/src/main/java/health/ere/ps/config/UserConfig.java
@@ -1,5 +1,9 @@
package health.ere.ps.config;
+import de.health.service.cetp.config.IRuntimeConfig;
+import de.health.service.cetp.config.IUserConfigurations;
+import de.health.service.cetp.config.UserRuntimeConfig;
+import de.health.service.cetp.konnektorconfig.KCUserConfigurations;
import health.ere.ps.event.config.UserConfigurationsUpdateEvent;
import health.ere.ps.model.config.UserConfigurations;
import health.ere.ps.service.config.UserConfigurationService;
@@ -13,7 +17,7 @@
import java.util.Optional;
@ApplicationScoped
-public class UserConfig {
+public class UserConfig implements UserRuntimeConfig {
@Inject
UserConfigurationService configurationManagementService;
@@ -55,6 +59,27 @@ void init() {
public UserConfig() {
}
+ @Override
+ public IUserConfigurations getUserConfigurations() {
+ return configurations;
+ }
+
+ @Override
+ public IRuntimeConfig getRuntimeConfig() {
+ if (this instanceof RuntimeConfig runtimeConfig) {
+ return runtimeConfig;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public UserRuntimeConfig copy() {
+ RuntimeConfig runtimeConfig = new RuntimeConfig();
+ runtimeConfig.copyValuesFromUserConfig(this);
+ return runtimeConfig;
+ }
+
public UserConfigurations getConfigurations() {
return configurations == null ? new UserConfigurations() : configurations;
}
@@ -119,8 +144,12 @@ public void handleUpdateProperties(@ObservesAsync UserConfigurationsUpdateEvent
updateProperties(event.getConfigurations());
}
- public void updateProperties(UserConfigurations configurations) {
- this.configurations = configurations;
+ public void updateProperties(IUserConfigurations configurations) {
+ if (configurations instanceof UserConfigurations) {
+ this.configurations = (UserConfigurations) configurations;
+ } else if (configurations instanceof KCUserConfigurations kcUserConfigurations) {
+ this.configurations = new UserConfigurations(kcUserConfigurations.properties());
+ }
}
private void updateProperties() {
diff --git a/src/main/java/health/ere/ps/jmx/StatusMXBeanImpl.java b/src/main/java/health/ere/ps/jmx/StatusMXBeanImpl.java
index 52241ad0c..9233fe01c 100644
--- a/src/main/java/health/ere/ps/jmx/StatusMXBeanImpl.java
+++ b/src/main/java/health/ere/ps/jmx/StatusMXBeanImpl.java
@@ -3,9 +3,9 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import de.health.service.cetp.SubscriptionManager;
import health.ere.ps.config.RuntimeConfig;
import health.ere.ps.model.status.Status;
-import health.ere.ps.service.cetp.SubscriptionManager;
import health.ere.ps.service.status.StatusService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
diff --git a/src/main/java/health/ere/ps/model/config/UserConfigurations.java b/src/main/java/health/ere/ps/model/config/UserConfigurations.java
index b0b639937..f4bc82506 100644
--- a/src/main/java/health/ere/ps/model/config/UserConfigurations.java
+++ b/src/main/java/health/ere/ps/model/config/UserConfigurations.java
@@ -1,5 +1,11 @@
package health.ere.ps.model.config;
+import de.health.service.cetp.config.IUserConfigurations;
+import jakarta.json.JsonObject;
+import jakarta.json.bind.annotation.JsonbNillable;
+import jakarta.json.bind.annotation.JsonbProperty;
+import jakarta.servlet.http.HttpServletRequest;
+
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
@@ -15,12 +21,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
-import jakarta.json.JsonObject;
-import jakarta.json.bind.annotation.JsonbNillable;
-import jakarta.json.bind.annotation.JsonbProperty;
-import jakarta.servlet.http.HttpServletRequest;
-
-public class UserConfigurations {
+public class UserConfigurations implements IUserConfigurations {
private static final Logger log = Logger.getLogger(UserConfigurations.class.getName());
diff --git a/src/main/java/health/ere/ps/resource/gematik/PharmacyResource.java b/src/main/java/health/ere/ps/resource/gematik/PharmacyResource.java
index 19de186e5..86e1e8540 100644
--- a/src/main/java/health/ere/ps/resource/gematik/PharmacyResource.java
+++ b/src/main/java/health/ere/ps/resource/gematik/PharmacyResource.java
@@ -1,9 +1,9 @@
package health.ere.ps.resource.gematik;
import de.gematik.ws.conn.vsds.vsdservice.v5.FaultMessage;
+import de.health.service.cetp.SubscriptionManager;
import health.ere.ps.config.RuntimeConfig;
import health.ere.ps.config.UserConfig;
-import health.ere.ps.service.cetp.SubscriptionManager;
import health.ere.ps.service.gematik.PharmacyService;
import jakarta.inject.Inject;
import jakarta.servlet.http.HttpServletRequest;
diff --git a/src/main/java/health/ere/ps/service/cardlink/AddJWTConfigurator.java b/src/main/java/health/ere/ps/service/cardlink/AddJWTConfigurator.java
index 52d1f0a9d..82cdbc81c 100644
--- a/src/main/java/health/ere/ps/service/cardlink/AddJWTConfigurator.java
+++ b/src/main/java/health/ere/ps/service/cardlink/AddJWTConfigurator.java
@@ -3,8 +3,8 @@
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.cetp.config.KonnektorConfig;
import health.ere.ps.service.connector.provider.MultiConnectorServicesProvider;
import health.ere.ps.service.gematik.PharmacyService;
import io.quarkus.arc.Unremovable;
diff --git a/src/main/java/health/ere/ps/service/cetp/CETPServer.java b/src/main/java/health/ere/ps/service/cetp/CETPServer.java
deleted file mode 100644
index 0273d3a5f..000000000
--- a/src/main/java/health/ere/ps/service/cetp/CETPServer.java
+++ /dev/null
@@ -1,184 +0,0 @@
-package health.ere.ps.service.cetp;
-
-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.cetp.config.KonnektorConfig;
-import health.ere.ps.service.cetp.tracker.TrackerService;
-import health.ere.ps.service.common.security.SecretsManagerService;
-import health.ere.ps.service.common.security.SecretsManagerService.KeyStoreType;
-import health.ere.ps.service.gematik.PharmacyService;
-import health.ere.ps.service.health.check.CardlinkWebsocketCheck;
-import io.netty.bootstrap.ServerBootstrap;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.ChannelOption;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.channel.socket.nio.NioServerSocketChannel;
-import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
-import io.netty.handler.logging.LogLevel;
-import io.netty.handler.logging.LoggingHandler;
-import io.netty.handler.ssl.ClientAuth;
-import io.netty.handler.ssl.SslContext;
-import io.netty.handler.ssl.SslContextBuilder;
-import io.netty.util.concurrent.EventExecutorGroup;
-import io.quarkus.runtime.ShutdownEvent;
-import io.quarkus.runtime.StartupEvent;
-import jakarta.annotation.Priority;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.enterprise.event.Observes;
-import jakarta.inject.Inject;
-
-import javax.net.ssl.KeyManagerFactory;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-@ApplicationScoped
-public class CETPServer {
-
- public static final int PORT = 8585;
-
- private static final Logger log = Logger.getLogger(CETPServer.class.getName());
-
- List bossGroups = new ArrayList<>();
- List workerGroups = new ArrayList<>();
-
- private final Map startedOnPorts = new HashMap<>();
-
- @Inject
- AppConfig appConfig;
-
- @Inject
- PharmacyService pharmacyService;
-
- @Inject
- SecretsManagerService secretsManagerService;
-
- @Inject
- SubscriptionManager subscriptionManager;
-
- @Inject
- TrackerService trackerService;
-
- @Inject
- CardlinkWebsocketCheck cardlinkWebsocketCheck;
-
- // Make sure subscription manager get's onStart first, before CETPServer at least!
- void onStart(@Observes @Priority(5200) StartupEvent ev) {
- run();
- }
-
- void onShutdown(@Observes ShutdownEvent ev) {
- log.info("Shutdown CETP Server on port " + appConfig.getCetpPort());
- if (workerGroups != null) {
- workerGroups.stream().filter(Objects::nonNull).forEach(EventExecutorGroup::shutdownGracefully);
- }
- if (bossGroups != null) {
- bossGroups.stream().filter(Objects::nonNull).forEach(EventExecutorGroup::shutdownGracefully);
- }
- }
-
- public Map getStartedOnPorts() {
- return startedOnPorts;
- }
-
- public void run() {
- for (KonnektorConfig config : subscriptionManager.getKonnektorConfigs(null)) {
- log.info("Running CETP Server on port " + config.getCetpPort() + " for cardlink server: " + config.getCardlinkEndpoint());
- runServer(config);
- }
- }
-
- private void runServer(KonnektorConfig config) {
- NioEventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
- bossGroups.add(bossGroup);
- NioEventLoopGroup workerGroup = new NioEventLoopGroup();
- workerGroups.add(workerGroup);
- Integer port = config.getCetpPort();
- try {
- ServerBootstrap b = new ServerBootstrap(); // (2)
- b.group(bossGroup, workerGroup)
- .channel(NioServerSocketChannel.class) // (3)
- .handler(new LoggingHandler(LogLevel.INFO))
- .childHandler(new ChannelInitializer() { // (4)
- @Override
- public void initChannel(SocketChannel ch) {
- try {
- SslContext sslContext = SslContextBuilder
- .forServer(getKeyFactoryManager(config))
- .clientAuth(ClientAuth.NONE)
- .build();
-
- CardlinkWebsocketClient websocketClient = new CardlinkWebsocketClient(
- config.getCardlinkEndpoint(),
- cardlinkWebsocketCheck
- );
- ch.pipeline()
- .addLast("ssl", sslContext.newHandler(ch.alloc()))
- .addLast("logging", new LoggingHandler(LogLevel.DEBUG))
- .addLast(new LengthFieldBasedFrameDecoder(65536, 4, 4, 0, 0))
- .addLast(new CETPDecoder(config.getUserConfigurations()))
- .addLast(new CETPServerHandler(
- trackerService,
- pharmacyService,
- websocketClient)
- );
- } catch (Exception e) {
- log.log(Level.WARNING, "Failed to create SSL context", e);
- }
- }
- })
- .option(ChannelOption.SO_BACKLOG, 128) // (5)
- .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
-
- // Bind and start to accept incoming connections.
-
- ChannelFuture f = b.bind(port).sync(); // (7)
- startedOnPorts.put(port.toString(), "STARTED");
-
- // Wait until the server socket is closed.
- // In this example, this does not happen, but you can do that to gracefully
- // shut down your server.
- f.channel().closeFuture(); //.sync();
- } catch (InterruptedException e) {
- startedOnPorts.put(port.toString(), String.format("FAILED: %s", e.getMessage()));
- log.log(Level.WARNING, "CETP Server interrupted", e);
- }
- }
-
-
- private KeyManagerFactory getKeyFactoryManager(KonnektorConfig config) {
- if (config.getUserConfigurations().getClientCertificate() == null) {
- return secretsManagerService.getKeyManagerFactory();
- } else {
- String connectorTlsCertAuthStorePwd = config.getUserConfigurations().getClientCertificatePassword();
- byte[] clientCertificateBytes = SecretsManagerService.getClientCertificateBytes(config.getUserConfigurations());
- try (ByteArrayInputStream certificateInputStream = new ByteArrayInputStream(clientCertificateBytes)) {
- KeyStore ks = KeyStore.getInstance(KeyStoreType.PKCS12.getKeyStoreType());
- ks.load(certificateInputStream, connectorTlsCertAuthStorePwd.toCharArray());
-
- KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- keyManagerFactory.init(ks, connectorTlsCertAuthStorePwd.toCharArray());
- return keyManagerFactory;
- } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException | CertificateException |
- IOException e) {
- log.log(Level.SEVERE, "Could not create keyManagerFactory", e);
- }
- }
- return null;
- }
-}
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 f0b0e0053..9bbcdea81 100644
--- a/src/main/java/health/ere/ps/service/cetp/CETPServerHandler.java
+++ b/src/main/java/health/ere/ps/service/cetp/CETPServerHandler.java
@@ -3,8 +3,8 @@
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.config.IUserConfigurations;
import health.ere.ps.config.RuntimeConfig;
-import health.ere.ps.model.config.UserConfigurations;
import health.ere.ps.service.cardlink.CardlinkWebsocketClient;
import health.ere.ps.service.cetp.tracker.TrackerService;
import health.ere.ps.service.gematik.PharmacyService;
@@ -24,7 +24,7 @@
import java.util.logging.Logger;
import java.util.stream.Collectors;
-import static health.ere.ps.utils.Utils.printException;
+import static de.health.service.cetp.utils.Utils.printException;
public class CETPServerHandler extends ChannelInboundHandlerAdapter {
@@ -62,7 +62,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
cardlinkWebsocketClient.connect();
@SuppressWarnings("unchecked")
- Pair input = (Pair) msg;
+ Pair input = (Pair) msg;
Event event = input.getKey();
if (event.getTopic().equals("CARD/INSERTED")) {
@@ -89,7 +89,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
log.fine(String.format("[%s] Card inserted: params: %s", correlationId, paramsStr));
try {
- UserConfigurations uc = input.getValue();
+ IUserConfigurations uc = input.getValue();
RuntimeConfig runtimeConfig = new RuntimeConfig(uc);
Pair pair = pharmacyService.getEPrescriptionsForCardHandle(
correlationId, cardHandle, null, runtimeConfig
diff --git a/src/main/java/health/ere/ps/service/cetp/CETPServerHandlerFactory.java b/src/main/java/health/ere/ps/service/cetp/CETPServerHandlerFactory.java
new file mode 100644
index 000000000..6a24dc6f7
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/CETPServerHandlerFactory.java
@@ -0,0 +1,43 @@
+package health.ere.ps.service.cetp;
+
+import de.health.service.cetp.CETPEventHandlerFactory;
+import de.health.service.cetp.konnektorconfig.KonnektorConfig;
+import health.ere.ps.service.cardlink.CardlinkWebsocketClient;
+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 io.netty.channel.ChannelInboundHandler;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+@ApplicationScoped
+public class CETPServerHandlerFactory implements CETPEventHandlerFactory {
+
+ TrackerService trackerService;
+ PharmacyService pharmacyService;
+ SecretsManagerService secretsManagerService;
+ CardlinkWebsocketCheck cardlinkWebsocketCheck;
+
+ @Inject
+ public CETPServerHandlerFactory(
+ TrackerService trackerService,
+ PharmacyService pharmacyService,
+ SecretsManagerService secretsManagerService,
+ CardlinkWebsocketCheck cardlinkWebsocketCheck
+ ) {
+ this.trackerService = trackerService;
+ this.pharmacyService = pharmacyService;
+ this.secretsManagerService = secretsManagerService;
+ this.cardlinkWebsocketCheck = cardlinkWebsocketCheck;
+ }
+
+ @Override
+ public ChannelInboundHandler build(KonnektorConfig konnektorConfig) {
+ CardlinkWebsocketClient cardlinkWebsocketClient = new CardlinkWebsocketClient(
+ konnektorConfig.getCardlinkEndpoint(),
+ cardlinkWebsocketCheck
+ );
+ 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 a61a3dfed..ef09f6073 100644
--- a/src/main/java/health/ere/ps/service/cetp/KonnektorClient.java
+++ b/src/main/java/health/ere/ps/service/cetp/KonnektorClient.java
@@ -5,56 +5,83 @@
import de.gematik.ws.conn.eventservice.v7.GetSubscription;
import de.gematik.ws.conn.eventservice.v7.GetSubscriptionResponse;
import de.gematik.ws.conn.eventservice.v7.RenewSubscriptionsResponse;
+import de.gematik.ws.conn.eventservice.v7.SubscriptionRenewal;
import de.gematik.ws.conn.eventservice.v7.SubscriptionType;
import de.gematik.ws.conn.eventservice.wsdl.v7.EventServicePortType;
import de.gematik.ws.conn.eventservice.wsdl.v7.FaultMessage;
-import health.ere.ps.config.RuntimeConfig;
+import de.health.service.cetp.IKonnektorClient;
+import de.health.service.cetp.config.UserRuntimeConfig;
+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.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.connector.provider.MultiConnectorServicesProvider;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.xml.ws.Holder;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.commons.lang3.tuple.Triple;
import javax.xml.datatype.XMLGregorianCalendar;
import java.util.List;
+import java.util.stream.Collectors;
-import static health.ere.ps.service.cetp.SubscriptionManager.FAILED;
+import static de.health.service.cetp.SubscriptionManager.FAILED;
@ApplicationScoped
-public class KonnektorClient {
+public class KonnektorClient implements IKonnektorClient {
- public static final String CARD_INSERTED_TOPIC = "CARD/INSERTED";
+ private final Object emptyInput = new Object();
@Inject
MultiConnectorServicesProvider connectorServicesProvider;
- public List getSubscriptions(RuntimeConfig runtimeConfig) throws FaultMessage {
+ @Inject
+ SubscriptionResultMapper subscriptionResultMapper;
+
+ @Inject
+ SubscriptionMapper subscriptionMapper;
+
+ @Inject
+ StatusMapper statusMapper;
+
+ @Override
+ public List getSubscriptions(UserRuntimeConfig runtimeConfig) throws CetpFault {
ContextType context = connectorServicesProvider.getContextType(runtimeConfig);
EventServicePortType eventService = connectorServicesProvider.getEventServicePortType(runtimeConfig);
GetSubscription getSubscriptionRequest = new GetSubscription();
getSubscriptionRequest.setContext(context);
getSubscriptionRequest.setMandantWide(false);
- GetSubscriptionResponse subscriptionResponse = eventService.getSubscription(getSubscriptionRequest);
- return subscriptionResponse.getSubscriptions().getSubscription();
+ try {
+ GetSubscriptionResponse subscriptionResponse = eventService.getSubscription(getSubscriptionRequest);
+ return subscriptionResponse.getSubscriptions().getSubscription()
+ .stream().map(subscriptionMapper::toDomain)
+ .collect(Collectors.toList());
+ } catch (FaultMessage faultMessage) {
+ throw new CetpFault(faultMessage.getMessage());
+ }
}
- public Pair renewSubscription(RuntimeConfig runtimeConfig, String subscriptionId) throws FaultMessage {
+ @Override
+ public SubscriptionResult renewSubscription(UserRuntimeConfig runtimeConfig, String subscriptionId) throws CetpFault {
ContextType context = connectorServicesProvider.getContextType(runtimeConfig);
EventServicePortType eventService = connectorServicesProvider.getEventServicePortType(runtimeConfig);
Holder statusHolder = new Holder<>();
Holder renewalHolder = new Holder<>();
List subscriptions = List.of(subscriptionId);
-
- eventService.renewSubscriptions(context, subscriptions, statusHolder, renewalHolder);
- return Pair.of(statusHolder.value, renewalHolder.value.getSubscriptionRenewal().get(0).getSubscriptionID());
+ try {
+ eventService.renewSubscriptions(context, subscriptions, statusHolder, renewalHolder);
+ SubscriptionRenewal renewal = renewalHolder.value.getSubscriptionRenewal().get(0);
+ return subscriptionResultMapper.toDomain(renewal, statusHolder);
+ } catch (FaultMessage faultMessage) {
+ throw new CetpFault(faultMessage.getMessage());
+ }
}
- public Triple subscribeToKonnektor(
- RuntimeConfig runtimeConfig,
- String cetpHost
- ) throws FaultMessage {
+ @Override
+ public SubscriptionResult subscribe(UserRuntimeConfig runtimeConfig, String cetpHost) throws CetpFault {
ContextType context = connectorServicesProvider.getContextType(runtimeConfig);
EventServicePortType eventService = connectorServicesProvider.getEventServicePortType(runtimeConfig);
@@ -62,32 +89,39 @@ public Triple subscribeToKonnektor(
subscriptionType.setEventTo(cetpHost);
subscriptionType.setTopic(CARD_INSERTED_TOPIC);
- Holder status = new Holder<>();
+ Holder statusHolder = new Holder<>();
Holder subscriptionId = new Holder<>();
Holder terminationTime = new Holder<>();
-
- eventService.subscribe(context, subscriptionType, status, subscriptionId, terminationTime);
-
- return Triple.of(status.value, subscriptionId.value, terminationTime.value.toString());
+ try {
+ eventService.subscribe(context, subscriptionType, statusHolder, subscriptionId, terminationTime);
+ return subscriptionResultMapper.toDomain(emptyInput, statusHolder, subscriptionId, terminationTime);
+ } catch (FaultMessage faultMessage) {
+ throw new CetpFault(faultMessage.getMessage());
+ }
}
- public Status unsubscribeFromKonnektor(
- RuntimeConfig runtimeConfig,
+ @Override
+ public CetpStatus unsubscribe(
+ UserRuntimeConfig runtimeConfig,
String subscriptionId,
String cetpHost,
boolean forceCetp
- ) throws FaultMessage {
+ ) throws CetpFault {
ContextType context = connectorServicesProvider.getContextType(runtimeConfig);
EventServicePortType eventService = connectorServicesProvider.getEventServicePortType(runtimeConfig);
- if (forceCetp) {
- return eventService.unsubscribe(context, null, cetpHost);
- } else {
- if (subscriptionId == null || subscriptionId.startsWith(FAILED)) {
- Status status = new Status();
- status.setResult("Previous subscription is not found");
- return status;
+ try {
+ if (forceCetp) {
+ return statusMapper.toDomain(eventService.unsubscribe(context, null, cetpHost));
+ } else {
+ if (subscriptionId == null || subscriptionId.startsWith(FAILED)) {
+ CetpStatus status = new CetpStatus();
+ status.setResult("Previous subscription is not found");
+ return status;
+ }
+ return statusMapper.toDomain(eventService.unsubscribe(context, subscriptionId, null));
}
- return eventService.unsubscribe(context, subscriptionId, null);
+ } catch (FaultMessage faultMessage) {
+ throw new CetpFault(faultMessage.getMessage());
}
}
}
diff --git a/src/main/java/health/ere/ps/service/cetp/LocalAddressInSameSubnetFinder.java b/src/main/java/health/ere/ps/service/cetp/LocalAddressInSameSubnetFinder.java
deleted file mode 100644
index 3ad356c22..000000000
--- a/src/main/java/health/ere/ps/service/cetp/LocalAddressInSameSubnetFinder.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package health.ere.ps.service.cetp;
-
-
-import com.google.common.annotations.VisibleForTesting;
-
-import java.net.*;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Most computers nowadays have multiple (possibly virtual) network interfaces attached and hence possibly listen
- * to multiple ip addresses.
- *
- * Given that we know some external IP address, we can check out our own network interfaces if we have one
- * ip address being in the same subnet as the external ip.
- *
- * This is especially useful in a scenario where we receive a broadcast UDP packet: Broadcasts can only be received
- * if one is in the same subnet as the broadcast sender. Hence, if we know the broadcaster ip, we can pretty
- * confidentally predict the network card (and IP address our lur local host) that received the broadcast to e.g.
- * respond to the broadcaster our own IP they can reach us (e.g. Gematik Konnektor).
- */
-public class LocalAddressInSameSubnetFinder {
-
- public static Inet4Address findLocalIPinSameSubnet(Inet4Address peer) throws SocketException {
- return findLocalIPinSameSubnet(Collections.list(NetworkInterface.getNetworkInterfaces()), peer);
- }
-
- public static Inet4Address findLocalIPinSameSubnet(List nics, Inet4Address peer) {
- return new LocalAddressInSameSubnetFinder().findHostAddress(nics, peer);
- }
-
- @VisibleForTesting
- LocalAddressInSameSubnetFinder() {
- // NOOP
- }
-
- @VisibleForTesting
- Inet4Address findHostAddress(List interfaces, Inet4Address peer) {
- if (peer == null) {
- return null;
- }
- Inet4Address bestMatch = null;
- int bestMatchPrefix = -1;
- for (NetworkInterface ni : interfaces) {
- if (isLoopBack(ni) || !isUp(ni)) {
- continue;
- }
-
- for (InterfaceAddress ia : ni.getInterfaceAddresses()) {
- InetAddress address = ia.getAddress();
- // Only support IPv4 address in this entire class currently.
- if ((address instanceof Inet4Address ip4address) && (ia.getNetworkPrefixLength() > bestMatchPrefix) && isInSubnet(ia, peer)) {
- bestMatch = ip4address;
- bestMatchPrefix = ia.getNetworkPrefixLength();
- }
- }
- }
-
- if (bestMatch != null) {
- return bestMatch;
- }
-
- return null;
- }
-
- @VisibleForTesting
- boolean isInSubnet(InterfaceAddress ifa, InetAddress ipAddress) {
- InetAddress networkAddress = ifa.getAddress();
- int networkPrefixLength = ifa.getNetworkPrefixLength();
-
- byte[] networkAddressBytes = networkAddress.getAddress();
- byte[] ipAddressBytes = ipAddress.getAddress();
-
- if (networkAddressBytes.length != ipAddressBytes.length) {
- // IPv4 and IPv6 length mismatch
- return false;
- }
-
- int byteCount = networkAddressBytes.length;
- int bitCount = networkPrefixLength;
-
- for (int i = 0; i < byteCount; i++) {
- int networkByte = networkAddressBytes[i] & 0xFF;
- int ipByte = ipAddressBytes[i] & 0xFF;
-
- // Calculate the mask for the current byte
- int mask = (bitCount >= 8) ? 0xFF : (0xFF << (8 - bitCount));
-
- // Apply the mask and compare
- if ((networkByte & mask) != (ipByte & mask)) {
- return false;
- }
-
- // Subtract the number of bits we just processed
- bitCount -= 8;
- if (bitCount <= 0) {
- break;
- }
- }
-
- return true;
- }
-
-
- private boolean isLoopBack(NetworkInterface nic) {
- try {
- return nic.isLoopback();
- } catch (SocketException e) {
- // Wrap to RTE, should not happen...
- throw new RuntimeException(e);
- }
- }
-
- private boolean isUp(NetworkInterface nic) {
- try {
- return nic.isUp();
- } catch (SocketException e) {
- // Wrap to RTE, should not happen...
- throw new RuntimeException(e);
- }
- }
-}
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 99b7af98c..7feb9255c 100644
--- a/src/main/java/health/ere/ps/service/cetp/RegisterSMCBJob.java
+++ b/src/main/java/health/ere/ps/service/cetp/RegisterSMCBJob.java
@@ -9,9 +9,12 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import de.health.service.cetp.SubscriptionManager;
+import de.health.service.cetp.konnektorconfig.KonnektorConfig;
+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.cetp.config.KonnektorConfig;
import health.ere.ps.service.health.check.CardlinkWebsocketCheck;
import io.quarkus.runtime.StartupEvent;
import io.quarkus.scheduler.Scheduled;
@@ -20,6 +23,8 @@
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
+import static health.ere.ps.jmx.PsMXBeanManager.registerMXBean;
+
@ApplicationScoped
public class RegisterSMCBJob {
@@ -41,6 +46,10 @@ void onStart(@Observes @Priority(5300) StartupEvent ev) {
private void initWSClients() {
Collection konnektorConfigs = subscriptionManager.getKonnektorConfigs(null);
+
+ SubscriptionsMXBeanImpl subscriptionsMXBean = new SubscriptionsMXBeanImpl(konnektorConfigs.size());
+ registerMXBean(SubscriptionsMXBean.OBJECT_NAME, subscriptionsMXBean);
+
cardlinkWebsocketClients = new ArrayList<>();
konnektorConfigs.forEach(kc ->
cardlinkWebsocketClients.add(new CardlinkWebsocketClient(
diff --git a/src/main/java/health/ere/ps/service/cetp/SubscriptionManager.java b/src/main/java/health/ere/ps/service/cetp/SubscriptionManager.java
deleted file mode 100644
index 7eaf0d642..000000000
--- a/src/main/java/health/ere/ps/service/cetp/SubscriptionManager.java
+++ /dev/null
@@ -1,391 +0,0 @@
-package health.ere.ps.service.cetp;
-
-import de.gematik.ws.conn.connectorcommon.v5.Status;
-import de.gematik.ws.conn.eventservice.v7.SubscriptionType;
-import de.gematik.ws.conn.eventservice.wsdl.v7.FaultMessage;
-import de.gematik.ws.tel.error.v2.Error;
-import health.ere.ps.config.AppConfig;
-import health.ere.ps.config.RuntimeConfig;
-import health.ere.ps.jmx.PsMXBeanManager;
-import health.ere.ps.jmx.SubscriptionsMXBean;
-import health.ere.ps.jmx.SubscriptionsMXBeanImpl;
-import health.ere.ps.retry.Retrier;
-import health.ere.ps.service.cetp.config.KonnektorConfig;
-import health.ere.ps.service.cetp.config.KonnektorConfigService;
-import io.quarkus.runtime.StartupEvent;
-import io.quarkus.scheduler.Scheduled;
-import jakarta.annotation.Priority;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.enterprise.event.Observes;
-import jakarta.inject.Inject;
-import jakarta.xml.ws.Holder;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.commons.lang3.tuple.Triple;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.time.OffsetDateTime;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
-import static health.ere.ps.utils.Utils.printException;
-
-@ApplicationScoped
-public class SubscriptionManager {
-
- private final static Logger log = Logger.getLogger(SubscriptionManager.class.getName());
-
- public static final String FAILED = "failed";
-
- private final Map hostToKonnektorConfig = new ConcurrentHashMap<>();
-
- AppConfig appConfig;
- KonnektorClient konnektorClient;
- KonnektorConfigService kcService;
-
- private ExecutorService threadPool;
-
- @Inject
- public SubscriptionManager(
- AppConfig appConfig,
- KonnektorClient konnektorClient,
- KonnektorConfigService kcService
- ) {
- this.appConfig = appConfig;
- this.konnektorClient = konnektorClient;
- this.kcService = kcService;
- }
-
- // Make sure subscription manager get's onStart first, before CETPServer at least!
- public void onStart(@Observes @Priority(5100) StartupEvent ev) {
- hostToKonnektorConfig.putAll(kcService.loadConfigs());
- threadPool = Executors.newFixedThreadPool(hostToKonnektorConfig.size());
- SubscriptionsMXBeanImpl subscriptionsMXBean = new SubscriptionsMXBeanImpl(hostToKonnektorConfig.size());
- PsMXBeanManager.registerMXBean(SubscriptionsMXBean.OBJECT_NAME, subscriptionsMXBean);
- }
-
- @Scheduled(
- every = "${cetp.subscription.maintenance.interval.sec:3s}",
- delay = 5,
- delayUnit = TimeUnit.SECONDS,
- concurrentExecution = Scheduled.ConcurrentExecution.SKIP
- )
- void subscriptionsMaintenance() {
- String defaultSender = appConfig.getEventToHost().orElse(null);
- if (defaultSender == null) {
- log.log(Level.WARNING, "You did not set 'cetp.subscriptions.event-to-host' property. Will have no fallback if Konnektor is not found to be in the same subnet");
- }
- List retryMillis = List.of(200);
- int intervalMs = appConfig.getSubscriptionsMaintenanceRetryIntervalMs();
- List> futures = getKonnektorConfigs(null).stream().map(kc -> threadPool.submit(() -> {
- Inet4Address meInSameSubnet = LocalAddressInSameSubnetFinder.findLocalIPinSameSubnet(konnektorToIp4(kc.getHost()));
- String eventToHost = (meInSameSubnet != null) ? meInSameSubnet.getHostAddress() : defaultSender;
- if (eventToHost == null) {
- log.log(Level.INFO, "Can't maintain subscription. Don't know my own address to tell konnektor about it");
- return false;
- }
- Boolean result = Retrier.callAndRetry(
- retryMillis,
- intervalMs,
- () -> renewSubscriptions(eventToHost, kc),
- bool -> bool
- );
- if (!result) {
- String msg = String.format(
- "[%s] Subscriptions maintenance is failed within %d ms retry", kc.getHost(), intervalMs);
- log.warning(msg);
- }
- return result;
- })).toList();
- for (Future future : futures) {
- try {
- future.get();
- } catch (Throwable e) {
- log.log(Level.SEVERE, "Subscriptions maintenance error", e);
- }
- }
- }
-
- public boolean renewSubscriptions(String eventToHost, KonnektorConfig kc) {
- Semaphore semaphore = kc.getSemaphore();
- if (semaphore.tryAcquire()) {
- try {
- RuntimeConfig runtimeConfig = modifyRuntimeConfig(null, kc);
- String cetpHost = "cetp://" + eventToHost + ":" + kc.getCetpPort();
- List subscriptions = konnektorClient.getSubscriptions(runtimeConfig)
- .stream().filter(st -> st.getEventTo().contains(eventToHost)).toList();
-
- Holder resultHolder = new Holder<>();
- if (subscriptions.isEmpty()) {
- return subscribe(kc, runtimeConfig, cetpHost, resultHolder);
- } else {
- Optional newestOpt = subscriptions.stream().max(
- Comparator.comparing(o -> o.getTerminationTime().toGregorianCalendar().getTime())
- );
- SubscriptionType newest = newestOpt.get();
- Date expireDate = newest.getTerminationTime().toGregorianCalendar().getTime();
- Date now = new Date();
- boolean expired = now.getTime() >= expireDate.getTime();
-
- // force re-subscribe every 12 hours
- int periodSeconds = appConfig.getForceResubscribePeriodSeconds();
- boolean forceSubscribe = kc.getSubscriptionTime().plusSeconds(periodSeconds).isBefore(OffsetDateTime.now());
- if (expired || forceSubscribe) {
- boolean subscribed = subscribe(kc, runtimeConfig, cetpHost, resultHolder);
- if (forceSubscribe && subscribed) {
- log.info(String.format("Force subscribed to %s: %s", kc.getHost(), resultHolder.value));
- }
- // all are expired, drop them
- boolean dropped = drop(runtimeConfig, subscriptions).isEmpty();
- return subscribed && dropped;
- } else {
- boolean renewed = renew(runtimeConfig, kc, newest, now, expireDate);
- List olderSubscriptions = subscriptions.stream()
- .filter(st -> !st.getSubscriptionID().equals(newest.getSubscriptionID()))
- .toList();
- boolean dropped = drop(runtimeConfig, olderSubscriptions).isEmpty();
- return renewed && dropped;
- }
- }
- } catch (FaultMessage fm) {
- log.log(Level.SEVERE, String.format("[%s] Subscriptions maintenance error", kc.getHost()), fm);
- return false;
- } finally {
- semaphore.release();
- }
- } else {
- log.warning(String.format("[%s] Subscription maintenance is in progress, try later", kc.getHost()));
- return true;
- }
- }
-
- public boolean renew(
- RuntimeConfig runtimeConfig,
- KonnektorConfig konnektorConfig,
- SubscriptionType type,
- Date now,
- Date expireDate
- ) throws FaultMessage {
- String newestSubscriptionId = type.getSubscriptionID();
- boolean sameSubscription = newestSubscriptionId.equals(konnektorConfig.getSubscriptionId());
- if (!sameSubscription) {
- String msg = String.format(
- "Found subscriptions discrepancy: CONFIG=%s, REAL=%s, REAL_EXPIRATION=%s, updating config",
- konnektorConfig.getSubscriptionId(),
- newestSubscriptionId,
- expireDate
- );
- log.warning(msg);
- kcService.saveSubscription(konnektorConfig, newestSubscriptionId, null);
- }
- int safePeriod = appConfig.getCetpSubscriptionsRenewalSafePeriodMs();
- if (now.getTime() + safePeriod >= expireDate.getTime()) {
- String msg = String.format(
- "Subscription %s is about to expire after %d seconds, renew", newestSubscriptionId, safePeriod / 1000
- );
- log.info(msg);
- Pair pair = konnektorClient.renewSubscription(runtimeConfig, newestSubscriptionId);
- Error error = pair.getKey().getError();
- String renewedSubscriptionId = pair.getValue();
- if (error == null && !renewedSubscriptionId.equals(newestSubscriptionId)) {
- msg = String.format(
- "Subscription ID has changed after renew: OLD=%s, NEW=%s, updating config",
- newestSubscriptionId,
- renewedSubscriptionId
- );
- log.fine(msg);
- kcService.saveSubscription(konnektorConfig, renewedSubscriptionId, null);
- }
- return error == null;
- } else {
- return true;
- }
- }
-
- private String printError(Error error) {
- return String.format(
- "[%s] Gematik ERROR at %s: %s ",
- error.getMessageID(),
- error.getTimestamp(),
- error.getTrace().stream().map(t ->
- String.format("Code=%s ErrorText=%s Detail=%s", t.getCode(), t.getErrorText(), t.getDetail().getValue())
- ).collect(Collectors.joining(", "))
- );
- }
-
- public List drop(
- RuntimeConfig runtimeConfig,
- List subscriptions
- ) throws FaultMessage {
- return subscriptions.stream().map(s -> {
- try {
- Status status = konnektorClient.unsubscribeFromKonnektor(runtimeConfig, s.getSubscriptionID(), null, false);
- Error error = status.getError();
- if (error == null) {
- return Pair.of(true, s.getSubscriptionID());
- } else {
- String msg = String.format("Failed to unsubscribe %s", s.getSubscriptionID());
- log.log(Level.SEVERE, msg, printError(error));
- return Pair.of(false, s.getSubscriptionID());
- }
- } catch (FaultMessage f) {
- String msg = String.format("Failed to unsubscribe %s", s.getSubscriptionID());
- log.log(Level.SEVERE, msg, f);
- return Pair.of(false, s.getSubscriptionID());
- }
- }).filter(p -> !p.getKey()).map(Pair::getValue).toList();
- }
-
- public Collection getKonnektorConfigs(String host) {
- return host == null
- ? hostToKonnektorConfig.values()
- : hostToKonnektorConfig.entrySet().stream().filter(entry -> entry.getKey().contains(host)).map(Map.Entry::getValue).toList();
- }
-
- private RuntimeConfig modifyRuntimeConfig(RuntimeConfig runtimeConfig, KonnektorConfig konnektorConfig) {
- if (runtimeConfig == null) {
- return new RuntimeConfig(konnektorConfig.getUserConfigurations());
- } else {
- runtimeConfig.updateProperties(konnektorConfig.getUserConfigurations());
- return runtimeConfig;
- }
- }
-
- public List manage(
- RuntimeConfig runtimeConfig,
- String host,
- String eventToHost,
- boolean forceCetp,
- boolean subscribe
- ) {
- Collection konnektorConfigs = getKonnektorConfigs(host);
- List statuses = konnektorConfigs.stream().map(kc -> {
- Semaphore semaphore = kc.getSemaphore();
- if (semaphore.tryAcquire()) {
- try {
- String cetpHost = "cetp://" + eventToHost + ":" + kc.getCetpPort();
- return process(kc, modifyRuntimeConfig(runtimeConfig, kc), cetpHost, forceCetp, subscribe);
- } finally {
- semaphore.release();
- }
- } else {
- try {
- String h = host == null ? kc.getHost() : host;
- String s = subscribe ? "subscription" : "unsubscription";
- return String.format("[%s] Host %s is in progress, try later", h, s);
- } catch (Exception e) {
- return e.getMessage();
- }
- }
- })
- .filter(Objects::nonNull)
- .toList();
-
- if (statuses.isEmpty()) {
- return List.of(String.format("No configuration is found for the given host: %s", host));
- }
- return statuses;
- }
-
- private boolean subscribe(
- KonnektorConfig konnektorConfig,
- RuntimeConfig runtimeConfig,
- String cetpHost,
- Holder resultHolder
- ) throws FaultMessage {
- Triple triple = konnektorClient.subscribeToKonnektor(runtimeConfig, cetpHost);
- Status status = triple.getLeft();
- Error error = status.getError();
- if (error == null) {
- String newSubscriptionId = triple.getMiddle();
- resultHolder.value = status.getResult() + " " + newSubscriptionId + " " + triple.getRight();
- kcService.saveSubscription(konnektorConfig, newSubscriptionId, null);
- log.info(String.format("Subscribe status for subscriptionId=%s: %s", newSubscriptionId, status.getResult()));
- return true;
- } else {
- String statusResult = printError(error);
- resultHolder.value = statusResult;
- String subscriptionId = konnektorConfig.getSubscriptionId();
- String fileName = subscriptionId != null && subscriptionId.startsWith(FAILED)
- ? subscriptionId
- : String.format("%s-%s", FAILED, subscriptionId);
-
- kcService.saveSubscription(konnektorConfig, fileName, statusResult);
- log.log(Level.WARNING, String.format("Could not subscribe -> %s", statusResult));
- return false;
- }
- }
-
- private String process(
- KonnektorConfig konnektorConfig,
- RuntimeConfig runtimeConfig,
- String cetpHost,
- boolean forceCetp,
- boolean subscribe
- ) {
- String subscriptionId = konnektorConfig.getSubscriptionId();
- String failedUnsubscriptionFileName = subscriptionId != null && subscriptionId.startsWith(FAILED)
- ? subscriptionId
- : String.format("%s-unsubscription-%s", FAILED, subscriptionId);
-
- String failedSubscriptionFileName = String.format("%s-subscription", FAILED);
-
- String statusResult;
- boolean unsubscribed = false;
- try {
- Status status = konnektorClient.unsubscribeFromKonnektor(runtimeConfig, subscriptionId, cetpHost, forceCetp);
- Error error = status.getError();
- if (error == null) {
- unsubscribed = true;
- statusResult = status.getResult();
- log.info(String.format("Unsubscribe status for subscriptionId=%s: %s", subscriptionId, statusResult));
- if (subscribe) {
- Holder resultHolder = new Holder<>();
- subscribe(konnektorConfig, runtimeConfig, cetpHost, resultHolder);
- statusResult = resultHolder.value;
- } else {
- kcService.cleanUp(konnektorConfig, null);
- }
- } else {
- statusResult = printError(error);
- kcService.saveSubscription(konnektorConfig, failedUnsubscriptionFileName, statusResult);
- String msg = String.format("Could not unsubscribe from %s -> %s", subscriptionId, printError(error));
- log.log(Level.WARNING, msg);
- }
- } catch (Exception e) {
- String fileName = unsubscribed ? failedSubscriptionFileName : failedUnsubscriptionFileName;
- kcService.saveSubscription(konnektorConfig, fileName, printException(e));
- log.log(Level.WARNING, "Error: " + fileName, e);
- statusResult = e.getMessage();
- }
- return statusResult;
- }
-
- private Inet4Address konnektorToIp4(String host) {
- try {
- InetAddress inetAddress = InetAddress.getByName(host);
- if (inetAddress instanceof Inet4Address addr) {
- return addr;
- } else {
- return null;
- }
- } catch (UnknownHostException e) {
- return null;
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/health/ere/ps/service/cetp/codec/CETPDecoder.java b/src/main/java/health/ere/ps/service/cetp/codec/CETPDecoder.java
index 53fd41ba5..f932759ca 100644
--- a/src/main/java/health/ere/ps/service/cetp/codec/CETPDecoder.java
+++ b/src/main/java/health/ere/ps/service/cetp/codec/CETPDecoder.java
@@ -6,6 +6,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import de.health.service.cetp.config.IUserConfigurations;
import org.apache.commons.lang3.tuple.Pair;
import de.gematik.ws.conn.eventservice.v7.Event;
@@ -29,13 +30,13 @@ public class CETPDecoder extends ByteToMessageDecoder {
log.log(Level.SEVERE, "Failed to create JAXB context", e);
}
}
- UserConfigurations userConfigurations;
+ IUserConfigurations userConfigurations;
public CETPDecoder() {
}
- public CETPDecoder(UserConfigurations userConfigurations) {
+ public CETPDecoder(IUserConfigurations userConfigurations) {
this.userConfigurations = userConfigurations;
}
diff --git a/src/main/java/health/ere/ps/service/cetp/codec/CETPDecoderFactory.java b/src/main/java/health/ere/ps/service/cetp/codec/CETPDecoderFactory.java
new file mode 100644
index 000000000..95adc51d8
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/codec/CETPDecoderFactory.java
@@ -0,0 +1,15 @@
+package health.ere.ps.service.cetp.codec;
+
+import de.health.service.cetp.codec.CETPEventDecoderFactory;
+import de.health.service.cetp.config.IUserConfigurations;
+import io.netty.channel.ChannelInboundHandler;
+import jakarta.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class CETPDecoderFactory implements CETPEventDecoderFactory {
+
+ @Override
+ public ChannelInboundHandler build(IUserConfigurations userConfigurations) {
+ return new CETPDecoder(userConfigurations);
+ }
+}
diff --git a/src/main/java/health/ere/ps/service/cetp/config/FSConfigService.java b/src/main/java/health/ere/ps/service/cetp/config/FSConfigService.java
deleted file mode 100644
index 5db66ba69..000000000
--- a/src/main/java/health/ere/ps/service/cetp/config/FSConfigService.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package health.ere.ps.service.cetp.config;
-
-import health.ere.ps.config.AppConfig;
-import health.ere.ps.config.UserConfig;
-import health.ere.ps.model.config.UserConfigurations;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.inject.Inject;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.time.Instant;
-import java.time.OffsetDateTime;
-import java.time.ZoneId;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
-import static health.ere.ps.service.cetp.SubscriptionManager.FAILED;
-import static health.ere.ps.utils.Utils.writeFile;
-
-@ApplicationScoped
-public class FSConfigService implements KonnektorConfigService {
-
- private final static Logger log = Logger.getLogger(FSConfigService.class.getName());
-
- public static final String PROPERTIES_EXT = ".properties";
-
- @ConfigProperty(name = "ere.per.konnektor.config.folder")
- String configFolder;
-
- @Inject
- AppConfig appConfig;
-
- @Inject
- UserConfig userConfig;
-
-
- @Override
- public Map loadConfigs() {
- List configs = new ArrayList<>();
- var konnektorConfigFolder = new File(configFolder);
- if (konnektorConfigFolder.exists()) {
- configs = readFromPath(konnektorConfigFolder.getAbsolutePath());
- }
- if (configs.isEmpty()) {
- configs.add(
- new KonnektorConfig(
- konnektorConfigFolder,
- appConfig.getCetpPort(),
- userConfig.getConfigurations(),
- appConfig.getCardLinkURI()
- )
- );
- }
- return configs.stream().collect(Collectors.toMap(this::getKonnectorKey, config -> config));
- }
-
- private String getKonnectorKey(KonnektorConfig config) {
- String konnectorHost = config.getHost();
- String host = konnectorHost == null ? appConfig.getKonnectorHost() : konnectorHost;
- return String.format("%d_%s", config.getCetpPort(), host);
- }
-
- public List readFromPath(String path) {
- File folderFile = new File(path);
- if (folderFile.exists() && folderFile.isDirectory()) {
- File[] files = folderFile.listFiles();
- if (files != null) {
- return Arrays.stream(files)
- .filter(File::isDirectory)
- .map(this::fromFolder)
- .filter(Objects::nonNull)
- .sorted(Comparator.comparing(KonnektorConfig::getCetpPort))
- .collect(Collectors.toList());
- }
- }
- return List.of();
- }
-
- private KonnektorConfig fromFolder(File folder) {
- Optional userPropertiesOpt = Arrays.stream(folder.listFiles())
- .filter(f -> f.getName().endsWith(PROPERTIES_EXT))
- .max(Comparator.comparingLong(File::lastModified));
-
- Optional subscriptionFileOpt = Arrays.stream(folder.listFiles())
- .filter(f -> !f.getName().startsWith(FAILED) && !f.getName().endsWith(PROPERTIES_EXT))
- .max(Comparator.comparingLong(File::lastModified));
-
- if (userPropertiesOpt.isPresent()) {
- File actualSubscription = userPropertiesOpt.get();
- if (actualSubscription.exists()) {
- String subscriptionId = subscriptionFileOpt.map(File::getName).orElse(null);
- OffsetDateTime subscriptionTime = subscriptionFileOpt
- .map(f -> OffsetDateTime.ofInstant(Instant.ofEpochMilli(f.lastModified()), ZoneId.systemDefault()))
- .orElse(OffsetDateTime.now().minusDays(30)); // force subscribe if no subscription is found
- try (var fis = new FileInputStream(actualSubscription)) {
- Properties properties = new Properties();
- properties.load(fis);
- KonnektorConfig konnektorConfig = new KonnektorConfig();
- konnektorConfig.cetpPort = Integer.parseInt(folder.getName());
- konnektorConfig.userConfigurations = new UserConfigurations(properties);
- konnektorConfig.cardlinkEndpoint = new URI(properties.getProperty("cardlinkServerURL"));
- konnektorConfig.subscriptionId = subscriptionId;
- konnektorConfig.subscriptionTime = subscriptionTime;
- konnektorConfig.folder = folder;
- return konnektorConfig;
- } catch (URISyntaxException | IOException e) {
- String msg = String.format(
- "Could not read konnektor config: folder=%s, subscriptionId=%s", folder.getName(), subscriptionId
- );
- log.log(Level.WARNING, msg, e);
- }
- }
- }
- return null;
- }
-
- @Override
- public void saveSubscription(KonnektorConfig konnektorConfig, String subscriptionId, String error) {
- try {
- writeFile(konnektorConfig.getFolder().getAbsolutePath() + "/" + subscriptionId, error);
- cleanUp(konnektorConfig, subscriptionId);
- konnektorConfig.setSubscriptionId(subscriptionId);
- konnektorConfig.setSubscriptionTime(OffsetDateTime.now());
- } catch (IOException e) {
- String msg = String.format(
- "Error while recreating subscription properties in folder: %s",
- konnektorConfig.getFolder().getAbsolutePath()
- );
- log.log(Level.SEVERE, msg, e);
- }
- }
-
- @Override
- public void cleanUp(KonnektorConfig konnektorConfig, String subscriptionId) {
- Arrays.stream(konnektorConfig.getFolder().listFiles())
- .filter(file -> !file.getName().equals(subscriptionId) && !file.getName().endsWith(PROPERTIES_EXT))
- .forEach(file -> {
- boolean deleted = file.delete();
- if (!deleted) {
- String msg = String.format("Unable to delete previous subscription file: %s", file.getName());
- log.log(Level.SEVERE, msg);
- file.renameTo(new File(String.format("%s_DELETING", file.getAbsolutePath())));
- }
- });
- }
-}
diff --git a/src/main/java/health/ere/ps/service/cetp/config/KonnektorConfig.java b/src/main/java/health/ere/ps/service/cetp/config/KonnektorConfig.java
deleted file mode 100644
index 8e37b16e0..000000000
--- a/src/main/java/health/ere/ps/service/cetp/config/KonnektorConfig.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package health.ere.ps.service.cetp.config;
-
-import health.ere.ps.model.config.UserConfigurations;
-
-import java.io.File;
-import java.net.URI;
-import java.time.OffsetDateTime;
-import java.util.concurrent.Semaphore;
-
-public class KonnektorConfig {
-
- File folder;
- Integer cetpPort;
- URI cardlinkEndpoint;
- String subscriptionId;
- OffsetDateTime subscriptionTime;
- UserConfigurations userConfigurations;
-
- private final Semaphore semaphore = new Semaphore(1);
-
- public KonnektorConfig() {
- }
-
- public KonnektorConfig(
- File folder,
- Integer cetpPort,
- UserConfigurations userConfigurations,
- URI cardlinkEndpoint
- ) {
- this.folder = folder;
- this.cetpPort = cetpPort;
- this.userConfigurations = userConfigurations;
- this.cardlinkEndpoint = cardlinkEndpoint;
-
- subscriptionId = null;
- subscriptionTime = OffsetDateTime.now().minusDays(30);
- }
-
- public Semaphore getSemaphore() {
- return semaphore;
- }
-
- public Integer getCetpPort() {
- return cetpPort;
- }
-
- public UserConfigurations getUserConfigurations() {
- return userConfigurations;
- }
-
- public String getHost() {
- String connectorBaseURL = userConfigurations.getConnectorBaseURL();
- return connectorBaseURL == null ? null : connectorBaseURL.split("//")[1];
- }
-
- public URI getCardlinkEndpoint() {
- return cardlinkEndpoint;
- }
-
- public String getSubscriptionId() {
- return subscriptionId;
- }
-
- public void setSubscriptionId(String subscriptionId) {
- this.subscriptionId = subscriptionId;
- }
-
- public File getFolder() {
- return folder;
- }
-
- public OffsetDateTime getSubscriptionTime() {
- return subscriptionTime;
- }
-
- public void setSubscriptionTime(OffsetDateTime subscriptionTime) {
- this.subscriptionTime = subscriptionTime;
- }
-}
diff --git a/src/main/java/health/ere/ps/service/cetp/config/KonnektorConfigService.java b/src/main/java/health/ere/ps/service/cetp/config/KonnektorConfigService.java
deleted file mode 100644
index 429d37bd3..000000000
--- a/src/main/java/health/ere/ps/service/cetp/config/KonnektorConfigService.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package health.ere.ps.service.cetp.config;
-
-import java.util.Map;
-
-public interface KonnektorConfigService {
-
- Map loadConfigs();
-
- void saveSubscription(KonnektorConfig konnektorConfig, String subscriptionId, String error);
-
- void cleanUp(KonnektorConfig konnektorConfig, String subscriptionId);
-}
diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/DefaultMappingConfig.java b/src/main/java/health/ere/ps/service/cetp/mapper/DefaultMappingConfig.java
new file mode 100644
index 000000000..fee23cd33
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/mapper/DefaultMappingConfig.java
@@ -0,0 +1,16 @@
+package health.ere.ps.service.cetp.mapper;
+
+import org.mapstruct.CollectionMappingStrategy;
+import org.mapstruct.MapperConfig;
+import org.mapstruct.NullValueCheckStrategy;
+import org.mapstruct.ReportingPolicy;
+
+@MapperConfig(
+ componentModel = "jakarta",
+ uses = {MapperUtils.class},
+ nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
+ unmappedTargetPolicy = ReportingPolicy.ERROR,
+ collectionMappingStrategy = CollectionMappingStrategy.TARGET_IMMUTABLE
+)
+public interface DefaultMappingConfig {
+}
diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/DetailMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/DetailMapper.java
new file mode 100644
index 000000000..32a29b6cc
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/mapper/DetailMapper.java
@@ -0,0 +1,10 @@
+package health.ere.ps.service.cetp.mapper;
+
+import de.health.service.cetp.domain.fault.Detail;
+import org.mapstruct.Mapper;
+
+@Mapper(config = DefaultMappingConfig.class)
+public interface DetailMapper {
+
+ Detail toDomain(de.gematik.ws.tel.error.v2.Error.Trace.Detail soap);
+}
diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/ErrorMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/ErrorMapper.java
new file mode 100644
index 000000000..cddd0025f
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/mapper/ErrorMapper.java
@@ -0,0 +1,12 @@
+package health.ere.ps.service.cetp.mapper;
+
+import de.health.service.cetp.domain.fault.Error;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper(config = DefaultMappingConfig.class, uses = {TraceMapper.class})
+public interface ErrorMapper {
+
+ @Mapping(source = "messageID", target = "messageId")
+ Error toDomain(de.gematik.ws.tel.error.v2.Error soap);
+}
diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/MapperUtils.java b/src/main/java/health/ere/ps/service/cetp/mapper/MapperUtils.java
new file mode 100644
index 000000000..903717065
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/mapper/MapperUtils.java
@@ -0,0 +1,12 @@
+package health.ere.ps.service.cetp.mapper;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+import java.util.Date;
+
+@SuppressWarnings("unused")
+public class MapperUtils {
+
+ public static Date calendarToDate(XMLGregorianCalendar calendar) {
+ return calendar.toGregorianCalendar().getTime();
+ }
+}
diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/StatusMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/StatusMapper.java
new file mode 100644
index 000000000..fc3c272e4
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/mapper/StatusMapper.java
@@ -0,0 +1,11 @@
+package health.ere.ps.service.cetp.mapper;
+
+import de.gematik.ws.conn.connectorcommon.v5.Status;
+import de.health.service.cetp.domain.CetpStatus;
+import org.mapstruct.Mapper;
+
+@Mapper(config = DefaultMappingConfig.class, uses = {ErrorMapper.class})
+public interface StatusMapper {
+
+ CetpStatus toDomain(Status soap);
+}
diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionMapper.java
new file mode 100644
index 000000000..602891a5f
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionMapper.java
@@ -0,0 +1,12 @@
+package health.ere.ps.service.cetp.mapper;
+
+import de.health.service.cetp.domain.eventservice.Subscription;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper(config = DefaultMappingConfig.class)
+public interface SubscriptionMapper {
+
+ @Mapping(source = "subscriptionID", target = "subscriptionId")
+ Subscription toDomain(de.gematik.ws.conn.eventservice.v7.SubscriptionType soap);
+}
diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionResultMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionResultMapper.java
new file mode 100644
index 000000000..f2e4bf156
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/mapper/SubscriptionResultMapper.java
@@ -0,0 +1,56 @@
+package health.ere.ps.service.cetp.mapper;
+
+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 jakarta.xml.ws.Holder;
+import org.mapstruct.AfterMapping;
+import org.mapstruct.Context;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingTarget;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+
+@Mapper(config = DefaultMappingConfig.class, uses = {StatusMapper.class})
+public abstract class SubscriptionResultMapper {
+
+ StatusMapperImpl statusMapper = new StatusMapperImpl();
+
+ @Mapping(source = "subscriptionID", target = "subscriptionId")
+ @Mapping(target = "status", ignore = true)
+ public abstract SubscriptionResult toDomain(SubscriptionRenewal soap, @Context Holder status);
+
+ @Mapping(target = "status", ignore = true)
+ @Mapping(target = "subscriptionId", ignore = true)
+ @Mapping(target = "terminationTime", ignore = true)
+ public abstract SubscriptionResult toDomain(
+ Object emptyInput,
+ @Context Holder status,
+ @Context Holder subscriptionId,
+ @Context Holder terminationTime
+ );
+
+ @AfterMapping
+ public void applyStatus(
+ @MappingTarget SubscriptionResult subscriptionResult,
+ @Context Holder status
+ ) {
+ CetpStatus domain = statusMapper.toDomain(status.value);
+ subscriptionResult.setStatus(domain);
+ }
+
+ @AfterMapping
+ public void applyStatus(
+ @MappingTarget SubscriptionResult subscriptionResult,
+ @Context Holder status,
+ @Context Holder subscriptionId,
+ @Context Holder terminationTime
+ ) {
+ CetpStatus domain = statusMapper.toDomain(status.value);
+ subscriptionResult.setStatus(domain);
+ subscriptionResult.setSubscriptionId(subscriptionId.value);
+ subscriptionResult.setTerminationTime(terminationTime.value.toGregorianCalendar().getTime());
+ }
+}
diff --git a/src/main/java/health/ere/ps/service/cetp/mapper/TraceMapper.java b/src/main/java/health/ere/ps/service/cetp/mapper/TraceMapper.java
new file mode 100644
index 000000000..09a802c06
--- /dev/null
+++ b/src/main/java/health/ere/ps/service/cetp/mapper/TraceMapper.java
@@ -0,0 +1,12 @@
+package health.ere.ps.service.cetp.mapper;
+
+import de.health.service.cetp.domain.fault.Trace;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper(config = DefaultMappingConfig.class, uses = {DetailMapper.class})
+public interface TraceMapper {
+
+ @Mapping(source = "eventID", target = "eventId")
+ Trace toDomain(de.gematik.ws.tel.error.v2.Error.Trace soap);
+}
diff --git a/src/main/java/health/ere/ps/service/cetp/tracker/TrackerService.java b/src/main/java/health/ere/ps/service/cetp/tracker/TrackerService.java
index 0ed984009..0c87120da 100644
--- a/src/main/java/health/ere/ps/service/cetp/tracker/TrackerService.java
+++ b/src/main/java/health/ere/ps/service/cetp/tracker/TrackerService.java
@@ -20,7 +20,7 @@
import java.util.logging.Logger;
import java.util.stream.Collectors;
-import static health.ere.ps.utils.Utils.terminateExecutor;
+import static de.health.service.cetp.utils.Utils.terminateExecutor;
@ApplicationScoped
public class TrackerService {
diff --git a/src/main/java/health/ere/ps/service/common/security/SecretsManagerService.java b/src/main/java/health/ere/ps/service/common/security/SecretsManagerService.java
index 97bfbe12b..0d96dfecc 100644
--- a/src/main/java/health/ere/ps/service/common/security/SecretsManagerService.java
+++ b/src/main/java/health/ere/ps/service/common/security/SecretsManagerService.java
@@ -1,5 +1,21 @@
package health.ere.ps.service.common.security;
+import de.health.service.cetp.FallbackSecretsManager;
+import de.health.service.cetp.config.IUserConfigurations;
+import health.ere.ps.config.AppConfig;
+import health.ere.ps.exception.common.security.SecretsManagerException;
+import health.ere.ps.model.config.UserConfigurations;
+import health.ere.ps.service.config.UserConfigurationService;
+import health.ere.ps.service.connector.endpoint.SSLUtilities;
+import jakarta.annotation.PostConstruct;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.event.Event;
+import jakarta.inject.Inject;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -18,23 +34,8 @@
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-
-import health.ere.ps.config.AppConfig;
-import health.ere.ps.exception.common.security.SecretsManagerException;
-import health.ere.ps.model.config.UserConfigurations;
-import health.ere.ps.service.config.UserConfigurationService;
-import health.ere.ps.service.connector.endpoint.SSLUtilities;
-import jakarta.annotation.PostConstruct;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.enterprise.event.Event;
-import jakarta.inject.Inject;
-
@ApplicationScoped
-public class SecretsManagerService {
+public class SecretsManagerService implements FallbackSecretsManager {
private static final Logger log = Logger.getLogger(SecretsManagerService.class.getName());
@@ -81,12 +82,11 @@ public SSLContext createSSLContext(UserConfigurations userConfigurations) {
}
}
- public static byte[] getClientCertificateBytes(UserConfigurations userConfigurations) {
+ private byte[] getClientCertificateBytes(IUserConfigurations userConfigurations) {
String base64UrlCertificate = userConfigurations.getClientCertificate();
String clientCertificateString = base64UrlCertificate.split(",")[1];
log.fine("Using certificate: "+clientCertificateString);
- byte[] clientCertificateBytes = Base64.getDecoder().decode(clientCertificateString);
- return clientCertificateBytes;
+ return Base64.getDecoder().decode(clientCertificateString);
}
public void acceptAllCertificates() {
@@ -147,6 +147,7 @@ public SSLContext getSslContext() {
return sslContext;
}
+ @Override
public KeyManagerFactory getKeyManagerFactory() {
return keyManagerFactory;
}
diff --git a/src/main/java/health/ere/ps/service/connector/endpoint/EndpointDiscoveryService.java b/src/main/java/health/ere/ps/service/connector/endpoint/EndpointDiscoveryService.java
index 09f0d6919..ea59c69c3 100644
--- a/src/main/java/health/ere/ps/service/connector/endpoint/EndpointDiscoveryService.java
+++ b/src/main/java/health/ere/ps/service/connector/endpoint/EndpointDiscoveryService.java
@@ -1,30 +1,29 @@
package health.ere.ps.service.connector.endpoint;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Base64;
-import java.util.Optional;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
+import de.health.service.cetp.config.IUserConfigurations;
+import de.health.service.cetp.config.UserRuntimeConfig;
+import health.ere.ps.config.AppConfig;
+import health.ere.ps.service.common.security.SecretsManagerService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.ProcessingException;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.client.Invocation.Builder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
-import health.ere.ps.config.AppConfig;
-import health.ere.ps.config.UserConfig;
-import health.ere.ps.service.common.security.SecretsManagerService;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Base64;
+import java.util.Optional;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* This service automatically discovers the endpoints that are available at the connector.
@@ -49,7 +48,7 @@ public class EndpointDiscoveryService {
@Inject
AppConfig appConfig;
@Inject
- UserConfig userConfig;
+ UserRuntimeConfig userConfig;
@Inject
SecretsManagerService secretsManagerService;
@@ -64,7 +63,7 @@ public EndpointDiscoveryService() {
}
- public EndpointDiscoveryService(UserConfig userConfig, SecretsManagerService secretsManagerService) {
+ public EndpointDiscoveryService(UserRuntimeConfig userConfig, SecretsManagerService secretsManagerService) {
this.userConfig = userConfig;
this.secretsManagerService = secretsManagerService;
}
@@ -92,8 +91,9 @@ public void obtainConfiguration(boolean throwEndpointException) throws IOExcepti
.path("/connector.sds")
.request();
- String basicAuthUsername = userConfig.getConfigurations().getBasicAuthUsername();
- String basicAuthPassword = userConfig.getConfigurations().getBasicAuthPassword();
+ IUserConfigurations userConfigurations = userConfig.getUserConfigurations();
+ String basicAuthUsername = userConfigurations.getBasicAuthUsername();
+ String basicAuthPassword = userConfigurations.getBasicAuthPassword();
if(basicAuthUsername != null && !basicAuthUsername.equals("")) {
builder.header("Authorization", "Basic "+Base64.getEncoder().encodeToString((basicAuthUsername+":"+basicAuthPassword).getBytes()));
}
@@ -208,10 +208,10 @@ private void extractAndSetConnectorVersion(Document document) {
if (versionContainingText.contains("PTV4+") || versionContainingText.contains("PTV4Plus")) {
log.info("Connector version PTV4+ found in connector.sds");
- userConfig.getConfigurations().setVersion("PTV4+");
+ userConfig.getUserConfigurations().setVersion("PTV4+");
} else if (versionContainingText.contains("PTV4")) {
log.info("Connector version PTV4 found in connector.sds");
- userConfig.getConfigurations().setVersion("PTV4");
+ userConfig.getUserConfigurations().setVersion("PTV4");
} else {
log.warning("Could not determine the version of the connector to use from connector.sds, " +
"using the one from the configuration:" + userConfig.getConnectorVersion());
diff --git a/src/main/java/health/ere/ps/service/connector/provider/AbstractConnectorServicesProvider.java b/src/main/java/health/ere/ps/service/connector/provider/AbstractConnectorServicesProvider.java
index ff1ff4b29..447a63356 100644
--- a/src/main/java/health/ere/ps/service/connector/provider/AbstractConnectorServicesProvider.java
+++ b/src/main/java/health/ere/ps/service/connector/provider/AbstractConnectorServicesProvider.java
@@ -1,14 +1,5 @@
package health.ere.ps.service.connector.provider;
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import jakarta.inject.Inject;
-import jakarta.xml.ws.BindingProvider;
-import javax.net.ssl.SSLContext;
-import javax.xml.parsers.ParserConfigurationException;
-
import de.gematik.ws.conn.authsignatureservice.wsdl.v7.AuthSignatureService;
import de.gematik.ws.conn.authsignatureservice.wsdl.v7.AuthSignatureServicePortType;
import de.gematik.ws.conn.cardservice.wsdl.v8.CardService;
@@ -24,11 +15,18 @@
import de.gematik.ws.conn.signatureservice.wsdl.v7.SignatureServiceV755;
import de.gematik.ws.conn.vsds.vsdservice.v5.VSDService;
import de.gematik.ws.conn.vsds.vsdservice.v5.VSDServicePortType;
-import health.ere.ps.config.UserConfig;
+import de.health.service.cetp.config.IUserConfigurations;
+import de.health.service.cetp.config.UserRuntimeConfig;
import health.ere.ps.config.interceptor.ProvidedConfig;
import health.ere.ps.service.common.security.SecretsManagerService;
import health.ere.ps.service.connector.endpoint.EndpointDiscoveryService;
import health.ere.ps.service.connector.endpoint.SSLUtilities;
+import jakarta.inject.Inject;
+import jakarta.xml.ws.BindingProvider;
+
+import javax.net.ssl.SSLContext;
+import java.util.logging.Level;
+import java.util.logging.Logger;
public abstract class AbstractConnectorServicesProvider {
private final static Logger log = Logger.getLogger(AbstractConnectorServicesProvider.class.getName());
@@ -213,8 +211,9 @@ private void configureBindingProvider(BindingProvider bindingProvider) {
bindingProvider.getRequestContext().put("com.sun.xml.ws.transport.https.client.hostname.verifier",
new SSLUtilities.FakeHostnameVerifier());
- String basicAuthUsername = getUserConfig().getConfigurations().getBasicAuthUsername();
- String basicAuthPassword = getUserConfig().getConfigurations().getBasicAuthPassword();
+ IUserConfigurations userConfigurations = getUserConfig().getUserConfigurations();
+ String basicAuthUsername = userConfigurations.getBasicAuthUsername();
+ String basicAuthPassword = userConfigurations.getBasicAuthPassword();
if(basicAuthUsername != null && !basicAuthUsername.equals("")) {
bindingProvider.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, basicAuthUsername);
@@ -262,5 +261,5 @@ public ContextType getContextType() {
return contextType;
}
- public abstract UserConfig getUserConfig();
+ public abstract UserRuntimeConfig getUserConfig();
}
diff --git a/src/main/java/health/ere/ps/service/connector/provider/DefaultConnectorServicesProvider.java b/src/main/java/health/ere/ps/service/connector/provider/DefaultConnectorServicesProvider.java
index 9ff5fa518..ffd822f09 100644
--- a/src/main/java/health/ere/ps/service/connector/provider/DefaultConnectorServicesProvider.java
+++ b/src/main/java/health/ere/ps/service/connector/provider/DefaultConnectorServicesProvider.java
@@ -1,16 +1,15 @@
package health.ere.ps.service.connector.provider;
+import de.health.service.cetp.config.UserRuntimeConfig;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
-import health.ere.ps.config.UserConfig;
-
@ApplicationScoped
public class DefaultConnectorServicesProvider extends AbstractConnectorServicesProvider {
@Inject
- UserConfig userConfig;
+ UserRuntimeConfig userConfig;
@PostConstruct
void init() {
@@ -18,7 +17,7 @@ void init() {
}
@Override
- public UserConfig getUserConfig() {
+ public UserRuntimeConfig getUserConfig() {
return userConfig;
}
diff --git a/src/main/java/health/ere/ps/service/connector/provider/MultiConnectorServicesProvider.java b/src/main/java/health/ere/ps/service/connector/provider/MultiConnectorServicesProvider.java
index 176249d63..cd782cf06 100644
--- a/src/main/java/health/ere/ps/service/connector/provider/MultiConnectorServicesProvider.java
+++ b/src/main/java/health/ere/ps/service/connector/provider/MultiConnectorServicesProvider.java
@@ -8,8 +8,8 @@
import de.gematik.ws.conn.signatureservice.wsdl.v7.SignatureServicePortTypeV740;
import de.gematik.ws.conn.signatureservice.wsdl.v7.SignatureServicePortTypeV755;
import de.gematik.ws.conn.vsds.vsdservice.v5.VSDServicePortType;
+import de.health.service.cetp.config.UserRuntimeConfig;
import health.ere.ps.config.SimpleUserConfig;
-import health.ere.ps.config.UserConfig;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Event;
import jakarta.inject.Inject;
@@ -17,7 +17,6 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
@ApplicationScoped
@@ -34,7 +33,7 @@ public class MultiConnectorServicesProvider {
//Map singleConnectorServicesProvider = new ConcurrentHashMap<>();
Map singleConnectorServicesProvider = Collections.synchronizedMap(new HashMap());
- public AbstractConnectorServicesProvider getSingleConnectorServicesProvider(UserConfig userConfig) {
+ public AbstractConnectorServicesProvider getSingleConnectorServicesProvider(UserRuntimeConfig userConfig) {
if (userConfig == null) {
return defaultConnectorServicesProvider;
} else {
@@ -48,35 +47,35 @@ public AbstractConnectorServicesProvider getSingleConnectorServicesProvider(User
}
}
- public CardServicePortType getCardServicePortType(UserConfig userConfig) {
+ public CardServicePortType getCardServicePortType(UserRuntimeConfig userConfig) {
return getSingleConnectorServicesProvider(userConfig).getCardServicePortType();
}
- public CertificateServicePortType getCertificateServicePortType(UserConfig userConfig) {
+ public CertificateServicePortType getCertificateServicePortType(UserRuntimeConfig userConfig) {
return getSingleConnectorServicesProvider(userConfig).getCertificateService();
}
- public EventServicePortType getEventServicePortType(UserConfig userConfig) {
+ public EventServicePortType getEventServicePortType(UserRuntimeConfig userConfig) {
return getSingleConnectorServicesProvider(userConfig).getEventServicePortType();
}
- public AuthSignatureServicePortType getAuthSignatureServicePortType(UserConfig userConfig) {
+ public AuthSignatureServicePortType getAuthSignatureServicePortType(UserRuntimeConfig userConfig) {
return getSingleConnectorServicesProvider(userConfig).getAuthSignatureServicePortType();
}
- public SignatureServicePortTypeV740 getSignatureServicePortType(UserConfig userConfig) {
+ public SignatureServicePortTypeV740 getSignatureServicePortType(UserRuntimeConfig userConfig) {
return getSingleConnectorServicesProvider(userConfig).getSignatureServicePortType();
}
- public SignatureServicePortTypeV755 getSignatureServicePortTypeV755(UserConfig userConfig) {
+ public SignatureServicePortTypeV755 getSignatureServicePortTypeV755(UserRuntimeConfig userConfig) {
return getSingleConnectorServicesProvider(userConfig).getSignatureServicePortTypeV755();
}
- public VSDServicePortType getVSDServicePortType(UserConfig userConfig) {
+ public VSDServicePortType getVSDServicePortType(UserRuntimeConfig userConfig) {
return getSingleConnectorServicesProvider(userConfig).getVSDServicePortType();
}
- public ContextType getContextType(UserConfig userConfig) {
+ public ContextType getContextType(UserRuntimeConfig userConfig) {
if (userConfig == null) {
return defaultConnectorServicesProvider.getContextType();
}
diff --git a/src/main/java/health/ere/ps/service/connector/provider/SingleConnectorServicesProvider.java b/src/main/java/health/ere/ps/service/connector/provider/SingleConnectorServicesProvider.java
index 1f9923525..3684bd2ef 100644
--- a/src/main/java/health/ere/ps/service/connector/provider/SingleConnectorServicesProvider.java
+++ b/src/main/java/health/ere/ps/service/connector/provider/SingleConnectorServicesProvider.java
@@ -1,7 +1,8 @@
package health.ere.ps.service.connector.provider;
+import de.health.service.cetp.config.IUserConfigurations;
+import de.health.service.cetp.config.UserRuntimeConfig;
import health.ere.ps.config.AppConfig;
-import health.ere.ps.config.UserConfig;
import health.ere.ps.service.common.security.SecretsManagerService;
import health.ere.ps.service.connector.endpoint.EndpointDiscoveryService;
import jakarta.enterprise.event.Event;
@@ -27,15 +28,16 @@
public class SingleConnectorServicesProvider extends AbstractConnectorServicesProvider {
private final static Logger log = Logger.getLogger(SingleConnectorServicesProvider.class.getName());
- UserConfig userConfig;
+ UserRuntimeConfig userConfig;
- public SingleConnectorServicesProvider(UserConfig userConfig, Event exceptionEvent) {
+ public SingleConnectorServicesProvider(UserRuntimeConfig userConfig, Event exceptionEvent) {
this.userConfig = userConfig;
this.secretsManagerService = new SecretsManagerService();
// Try to read SSL Certificates from the userConfig (this can also be the runtime config)
- String configKeystoreUri = userConfig.getConfigurations().getClientCertificate();
- String configKeystorePass = userConfig.getConfigurations().getClientCertificatePassword();
+ IUserConfigurations userConfigurations = userConfig.getUserConfigurations();
+ String configKeystoreUri = userConfigurations.getClientCertificate();
+ String configKeystorePass = userConfigurations.getClientCertificatePassword();
if (configKeystoreUri != null && !configKeystoreUri.isEmpty()) {
try {
@@ -159,7 +161,7 @@ public String[] getServerAliases(String arg0, Principal[] arg1) {
}
}
- public UserConfig getUserConfig() {
+ public UserRuntimeConfig getUserConfig() {
return userConfig;
}
}
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 d69468f7b..5c311058c 100644
--- a/src/main/java/health/ere/ps/service/gematik/PharmacyService.java
+++ b/src/main/java/health/ere/ps/service/gematik/PharmacyService.java
@@ -5,19 +5,17 @@
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.github.benmanes.caffeine.cache.Caffeine;
-import com.github.benmanes.caffeine.cache.LoadingCache;
import de.gematik.ws.conn.cardservicecommon.v2.CardTypeType;
import de.gematik.ws.conn.connectorcontext.v2.ContextType;
-import de.gematik.ws.conn.eventservice.v7.SubscriptionType;
import de.gematik.ws.conn.eventservice.wsdl.v7.EventServicePortType;
import de.gematik.ws.conn.vsds.vsdservice.v5.FaultMessage;
import de.gematik.ws.conn.vsds.vsdservice.v5.VSDServicePortType;
import de.gematik.ws.conn.vsds.vsdservice.v5.VSDStatusType;
+import de.health.service.cetp.IKonnektorClient;
+import de.health.service.cetp.domain.eventservice.Subscription;
import health.ere.ps.config.AppConfig;
import health.ere.ps.config.RuntimeConfig;
import health.ere.ps.jmx.ReadEPrescriptionsMXBeanImpl;
-import health.ere.ps.service.cetp.KonnektorClient;
import health.ere.ps.service.connector.provider.MultiConnectorServicesProvider;
import health.ere.ps.service.fhir.FHIRService;
import health.ere.ps.service.idp.BearerTokenService;
@@ -56,8 +54,11 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
-import java.time.Duration;
-import java.util.*;
+import java.util.Base64;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
@@ -68,7 +69,6 @@
import java.util.stream.Stream;
import java.util.zip.GZIPInputStream;
-
/* 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 {
@@ -87,7 +87,7 @@ public class PharmacyService implements AutoCloseable {
AppConfig appConfig;
@Inject
- KonnektorClient konnektorClient;
+ IKonnektorClient konnektorClient;
@Inject
MultiConnectorServicesProvider connectorServicesProvider;
@@ -196,9 +196,9 @@ public Holder readVSD(
try {
String listString;
try {
- List subscriptions = konnektorClient.getSubscriptions(runtimeConfig);
+ List subscriptions = konnektorClient.getSubscriptions(runtimeConfig);
listString = subscriptions.stream()
- .map(s -> String.format("[id=%s eventTo=%s topic=%s]", s.getSubscriptionID(), s.getEventTo(), s.getTopic()))
+ .map(s -> String.format("[id=%s eventTo=%s topic=%s]", s.getSubscriptionId(), s.getEventTo(), s.getTopic()))
.collect(Collectors.joining(","));
} catch (Throwable e) {
String msg = String.format("[%s] Could not get active getSubscriptions", correlationId);
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 6d339942f..8672b7153 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,10 +2,11 @@
import health.ere.ps.config.RuntimeConfig;
import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.context.Dependent;
import java.util.Map;
-@ApplicationScoped
+@Dependent
public class CardlinkWebsocketCheck implements Check {
private boolean connected;
diff --git a/src/main/java/health/ere/ps/service/health/check/CetpServerCheck.java b/src/main/java/health/ere/ps/service/health/check/CetpServerCheck.java
index 3d39edaab..9ff68162f 100644
--- a/src/main/java/health/ere/ps/service/health/check/CetpServerCheck.java
+++ b/src/main/java/health/ere/ps/service/health/check/CetpServerCheck.java
@@ -1,7 +1,7 @@
package health.ere.ps.service.health.check;
+import de.health.service.cetp.CETPServer;
import health.ere.ps.config.RuntimeConfig;
-import health.ere.ps.service.cetp.CETPServer;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
diff --git a/src/main/java/health/ere/ps/utils/Utils.java b/src/main/java/health/ere/ps/utils/Utils.java
deleted file mode 100644
index 7c20b2278..000000000
--- a/src/main/java/health/ere/ps/utils/Utils.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package health.ere.ps.utils;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.Optional;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Predicate;
-
-public class Utils {
-
- private static final Logger log = LoggerFactory.getLogger(Utils.class);
-
- public static void writeFile(String absolutePath, String content) throws IOException {
- try (FileOutputStream os = new FileOutputStream(absolutePath)) {
- if (content != null) {
- os.write(content.getBytes());
- }
- os.flush();
- }
- }
-
- public static boolean deleteFiles(File folder, Predicate predicate) {
- AtomicBoolean result = new AtomicBoolean(true);
- Arrays.stream(folder.listFiles())
- .filter(predicate)
- .forEach(file -> result.set(result.get() & file.delete()));
- return result.get();
- }
-
- public static String printException(Throwable e) {
- StringWriter sw = new StringWriter();
- e.printStackTrace(new PrintWriter(sw));
- String stacktrace = sw.toString();
- return e.getMessage() + " -> " + stacktrace;
- }
-
- public static Optional getHostFromNetworkInterfaces() {
- Inet4Address localAddress = null;
- try {
- Enumeration e = NetworkInterface.getNetworkInterfaces();
- while (e.hasMoreElements()) {
- NetworkInterface n = e.nextElement();
- Enumeration ee = n.getInetAddresses();
- while (ee.hasMoreElements()) {
- InetAddress i = ee.nextElement();
- if (i instanceof Inet4Address && i.getAddress()[0] != 127) {
- localAddress = (Inet4Address) i;
- break;
- }
- }
- }
- } catch (SocketException ignored) {
- }
- return localAddress == null
- ? Optional.empty()
- : Optional.of(localAddress.getHostAddress());
- }
-
- public static void terminateExecutor(ExecutorService executorService, String executorName, int awaitMillis) {
- if (executorService != null) {
- log.info(String.format("[%s] Terminating", executorName));
- executorService.shutdown();
- try {
- if (!executorService.awaitTermination(awaitMillis, TimeUnit.MILLISECONDS)) {
- executorService.shutdownNow();
- if (!executorService.awaitTermination(awaitMillis, TimeUnit.MILLISECONDS)) {
- log.info(String.format("[%s] Is not terminated", executorName));
- }
- }
- } catch (InterruptedException ex) {
- executorService.shutdownNow();
- Thread.currentThread().interrupt();
- }
- }
- }
-}
diff --git a/src/main/resources/META-INF/resources/frontend b/src/main/resources/META-INF/resources/frontend
index 509e4a807..7a1eb2279 160000
--- a/src/main/resources/META-INF/resources/frontend
+++ b/src/main/resources/META-INF/resources/frontend
@@ -1 +1 @@
-Subproject commit 509e4a807b428b0edb40ac28373d6b92462a44e8
+Subproject commit 7a1eb2279df59a3696acd61b7d9bb78baf4d330f
diff --git a/src/test/java/health/ere/ps/service/cetp/KonnektorFailedUnsubscriptionTest.java b/src/test/java/health/ere/ps/service/cetp/KonnektorFailedUnsubscriptionTest.java
index 38a65fb84..ca5cb1d3b 100644
--- a/src/test/java/health/ere/ps/service/cetp/KonnektorFailedUnsubscriptionTest.java
+++ b/src/test/java/health/ere/ps/service/cetp/KonnektorFailedUnsubscriptionTest.java
@@ -5,8 +5,9 @@
import de.gematik.ws.conn.eventservice.wsdl.v7.EventServicePortType;
import de.gematik.ws.conn.eventservice.wsdl.v7.FaultMessage;
import de.gematik.ws.tel.error.v2.Error;
+import de.health.service.cetp.SubscriptionManager;
+import de.health.service.cetp.konnektorconfig.FSConfigService;
import health.ere.ps.profile.RUDevTestProfile;
-import health.ere.ps.service.cetp.config.FSConfigService;
import health.ere.ps.service.connector.provider.MultiConnectorServicesProvider;
import io.quarkus.test.junit.QuarkusMock;
import io.quarkus.test.junit.QuarkusTest;
@@ -28,8 +29,8 @@
import java.util.List;
import java.util.UUID;
-import static health.ere.ps.utils.Utils.deleteFiles;
-import static health.ere.ps.utils.Utils.writeFile;
+import static de.health.service.cetp.utils.Utils.deleteFiles;
+import static de.health.service.cetp.utils.Utils.writeFile;
import static io.restassured.RestAssured.given;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
diff --git a/src/test/java/health/ere/ps/service/cetp/LocalAddressInSameSubnetFinderTest.java b/src/test/java/health/ere/ps/service/cetp/LocalAddressInSameSubnetFinderTest.java
deleted file mode 100644
index f394b05dd..000000000
--- a/src/test/java/health/ere/ps/service/cetp/LocalAddressInSameSubnetFinderTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package health.ere.ps.service.cetp;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-
-import java.net.*;
-import java.util.Arrays;
-import java.util.List;
-
-public class LocalAddressInSameSubnetFinderTest {
-
- @Test
- public void subnetMatch() throws UnknownHostException {
- LocalAddressInSameSubnetFinder ipFinder = new LocalAddressInSameSubnetFinder();
- Assertions.assertTrue(ipFinder.isInSubnet(
- createInterfaceAddress(
- InetAddress.getByName("192.168.178.15"),
- InetAddress.getByName("192.168.178.255"),
- (short) 24
- ),
- InetAddress.getByName("192.168.178.200")
- ));
- }
-
- @Test
- public void subnetSmallMaskNoMatch() throws UnknownHostException {
- LocalAddressInSameSubnetFinder ipFinder = new LocalAddressInSameSubnetFinder();
- Assertions.assertFalse(ipFinder.isInSubnet(
- createInterfaceAddress(
- InetAddress.getByName("192.168.178.14"),
- InetAddress.getByName("192.168.178.15"),
- (short) 30
- ),
- InetAddress.getByName("192.168.178.200")
- ));
- }
-
- @Test
- public void allSubnetMatch() throws UnknownHostException {
- LocalAddressInSameSubnetFinder ipFinder = new LocalAddressInSameSubnetFinder();
- Assertions.assertTrue(ipFinder.isInSubnet(
- createInterfaceAddress(
- InetAddress.getByName("192.168.178.15"),
- InetAddress.getByName("255.255.255.255"),
- (short) 0
- ),
- InetAddress.getByName("10.10.13.15")
- ));
- }
-
- @Test
- public void localIPskipLoopback() throws Exception {
- LocalAddressInSameSubnetFinder ipFinder = new LocalAddressInSameSubnetFinder();
- Inet4Address result = ipFinder.findHostAddress(
- List.of(
- createNetworkInterface(
- true, true,
- createInterfaceAddress(
- InetAddress.getByName("192.168.178.10"),
- InetAddress.getByName("192.168.178.255"),
- (short) 24
- )
- ),
- createNetworkInterface(
- false, true,
- createInterfaceAddress(
- InetAddress.getByName("192.168.10.10"),
- InetAddress.getByName("192.168.255.255"),
- (short) 16
- )
- )
- ),
- (Inet4Address) InetAddress.getByName("192.168.10.15")
- );
-
- // If first NIC wasn't a loopback, the first should have matched due to smaller subnet/better match.
- Assertions.assertEquals( "192.168.10.10", result.getHostAddress());
- }
-
- @Test
- public void localIPbestMatch() throws Exception {
- LocalAddressInSameSubnetFinder serviceDiscoveryRequestHandler = new LocalAddressInSameSubnetFinder();
- Inet4Address result = serviceDiscoveryRequestHandler.findHostAddress(
- List.of(
- createNetworkInterface(
- false, true,
- createInterfaceAddress(
- InetAddress.getByName("192.168.178.10"),
- InetAddress.getByName("192.168.178.255"),
- (short) 24
- )
- ),
- createNetworkInterface(
- false, true,
- createInterfaceAddress(
- InetAddress.getByName("192.168.10.10"),
- InetAddress.getByName("192.168.255.255"),
- (short) 16
- )
- )
- ),
- (Inet4Address) InetAddress.getByName("192.168.178.15")
- );
-
- Assertions.assertEquals(result.getHostAddress(), "192.168.178.10");
- }
-
- private NetworkInterface createNetworkInterface(boolean isLoopback, boolean isUp, InterfaceAddress... ifAddresses) throws SocketException {
- NetworkInterface result = Mockito.mock(NetworkInterface.class);
- Mockito.when(result.isLoopback()).thenReturn(isLoopback);
- Mockito.when(result.isUp()).thenReturn(isUp);
- Mockito.when(result.getInterfaceAddresses()).thenReturn(Arrays.asList(ifAddresses));
- return result;
- }
-
-
- private InterfaceAddress createInterfaceAddress(InetAddress address, InetAddress broadcast, short networkPrefixLength) {
- InterfaceAddress result = Mockito.mock(InterfaceAddress.class);
- Mockito.when(result.getAddress()).thenReturn(address);
- Mockito.when(result.getBroadcast()).thenReturn(broadcast);
- Mockito.when(result.getNetworkPrefixLength()).thenReturn(networkPrefixLength);
- return result;
- }
-}
diff --git a/src/test/java/health/ere/ps/service/cetp/SubscriptionRenewalTest.java b/src/test/java/health/ere/ps/service/cetp/SubscriptionRenewalTest.java
index d70fbf9c7..58b5963f1 100644
--- a/src/test/java/health/ere/ps/service/cetp/SubscriptionRenewalTest.java
+++ b/src/test/java/health/ere/ps/service/cetp/SubscriptionRenewalTest.java
@@ -8,8 +8,9 @@
import de.gematik.ws.conn.eventservice.v7.SubscriptionType;
import de.gematik.ws.conn.eventservice.wsdl.v7.EventServicePortType;
import de.gematik.ws.tel.error.v2.Error;
+import de.health.service.cetp.SubscriptionManager;
+import de.health.service.cetp.konnektorconfig.KonnektorConfig;
import health.ere.ps.profile.RUDevTestProfile;
-import health.ere.ps.service.cetp.config.KonnektorConfig;
import health.ere.ps.service.connector.provider.MultiConnectorServicesProvider;
import io.quarkus.test.junit.QuarkusMock;
import io.quarkus.test.junit.QuarkusTest;
@@ -30,7 +31,7 @@
import java.util.UUID;
import java.util.concurrent.TimeUnit;
-import static health.ere.ps.utils.Utils.getHostFromNetworkInterfaces;
+import static de.health.service.cetp.utils.Utils.getHostFromNetworkInterfaces;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
diff --git a/src/test/java/health/ere/ps/service/cetp/config/KonnektorConfigTest.java b/src/test/java/health/ere/ps/service/cetp/config/KonnektorConfigTest.java
index 52e15fc3a..e06597756 100644
--- a/src/test/java/health/ere/ps/service/cetp/config/KonnektorConfigTest.java
+++ b/src/test/java/health/ere/ps/service/cetp/config/KonnektorConfigTest.java
@@ -1,7 +1,15 @@
package health.ere.ps.service.cetp.config;
+import de.health.service.cetp.SubscriptionManager;
+import de.health.service.cetp.konnektorconfig.FSConfigService;
+import de.health.service.cetp.konnektorconfig.KonnektorConfig;
+import health.ere.ps.config.AppConfig;
+import health.ere.ps.config.UserConfig;
import health.ere.ps.model.config.UserConfigurations;
-import health.ere.ps.service.cetp.SubscriptionManager;
+import health.ere.ps.profile.RUDevTestProfile;
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.TestProfile;
+import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
@@ -16,12 +24,20 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
+@QuarkusTest
+@TestProfile(RUDevTestProfile.class)
public class KonnektorConfigTest {
+ @Inject
+ AppConfig appConfig;
+
+ @Inject
+ UserConfig userConfig;
+
@Test
void testGenerateKonnektorConfig() {
- FSConfigService configService = new FSConfigService();
- configService.configFolder = "src/test/resources/config/konnektoren/";
+ FSConfigService configService = new FSConfigService(appConfig, userConfig);
+ configService.setConfigFolder("src/test/resources/config/konnektoren/");
var configs = configService.loadConfigs();
assertEquals(3, configs.size());
@@ -42,8 +58,8 @@ void testGenerateKonnektorConfig() {
@Test
public void twoConfigsWithSameKonnectorAreLoaded() {
- FSConfigService configService = spy(new FSConfigService());
- configService.configFolder = "config/konnektoren";
+ FSConfigService configService = spy(new FSConfigService(appConfig, userConfig));
+ configService.setConfigFolder("config/konnektoren");
List sameKonnektorConfigs = new ArrayList<>();
Properties sameKonnektorProperties = new Properties();
@@ -54,7 +70,7 @@ public void twoConfigsWithSameKonnectorAreLoaded() {
doReturn(sameKonnektorConfigs).when(configService).readFromPath(any());
- SubscriptionManager subscriptionManager = new SubscriptionManager(null, null, configService);
+ SubscriptionManager subscriptionManager = new SubscriptionManager(appConfig, userConfig, null, configService);
subscriptionManager.onStart(null);
Collection konnektorConfigs = subscriptionManager.getKonnektorConfigs(konnektorHost);
assertEquals(sameKonnektorConfigs.size(), konnektorConfigs.size());
diff --git a/src/test/java/health/ere/ps/service/cetp/config/KonnektorSubscriptionTest.java b/src/test/java/health/ere/ps/service/cetp/config/KonnektorSubscriptionTest.java
index 41e83c21f..7e3967d90 100644
--- a/src/test/java/health/ere/ps/service/cetp/config/KonnektorSubscriptionTest.java
+++ b/src/test/java/health/ere/ps/service/cetp/config/KonnektorSubscriptionTest.java
@@ -3,10 +3,10 @@
import de.gematik.ws.conn.connectorcommon.v5.Status;
import de.gematik.ws.conn.connectorcontext.v2.ContextType;
import de.gematik.ws.conn.eventservice.wsdl.v7.EventServicePortType;
+import de.health.service.cetp.SubscriptionManager;
+import de.health.service.cetp.konnektorconfig.FSConfigService;
+import de.health.service.cetp.konnektorconfig.KonnektorConfigService;
import health.ere.ps.profile.RUDevTestProfile;
-import health.ere.ps.service.cetp.SubscriptionManager;
-import health.ere.ps.service.cetp.config.FSConfigService;
-import health.ere.ps.service.cetp.config.KonnektorConfigService;
import health.ere.ps.service.connector.provider.MultiConnectorServicesProvider;
import io.quarkus.test.junit.QuarkusMock;
import io.quarkus.test.junit.QuarkusTest;
@@ -106,7 +106,7 @@ public void beforeEach() throws Exception {
new File(TEMP_CONFIG).delete();
if (konnektorConfigService instanceof FSConfigService fsConfigService) {
- fsConfigService.configFolder = "config/konnektoren";
+ fsConfigService.setConfigFolder("config/konnektoren");
}
}
@@ -150,7 +150,7 @@ public void fakeFolderConfigKonnektorSubscriptionReloadedWhenHostMatchesAppConfi
Pair pair = prepareTempConfigFolder();
if (pair.getKey()) {
if (konnektorConfigService instanceof FSConfigService fsConfigService) {
- fsConfigService.configFolder = pair.getValue();
+ fsConfigService.setConfigFolder(pair.getValue());
subscriptionManager.onStart(null);
}
Response response = given()
@@ -172,7 +172,7 @@ public void fakeFolderConfigKonnektorSubscriptionNotReloadedWhenHostDoesntMatchA
Pair pair = prepareTempConfigFolder();
if (pair.getKey()) {
if (konnektorConfigService instanceof FSConfigService fsConfigService) {
- fsConfigService.configFolder = pair.getValue();
+ fsConfigService.setConfigFolder(pair.getValue());
subscriptionManager.onStart(null);
}
String host = "192.168.178.52";
diff --git a/src/test/java/health/ere/ps/service/cetp/tracker/TrackerTest.java b/src/test/java/health/ere/ps/service/cetp/tracker/TrackerTest.java
index 77888b64e..428de4c37 100644
--- a/src/test/java/health/ere/ps/service/cetp/tracker/TrackerTest.java
+++ b/src/test/java/health/ere/ps/service/cetp/tracker/TrackerTest.java
@@ -20,8 +20,8 @@
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
+import static de.health.service.cetp.utils.Utils.deleteFiles;
import static health.ere.ps.service.cetp.tracker.TrackerService.REQUESTS_CSV;
-import static health.ere.ps.utils.Utils.deleteFiles;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;