diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 572e8fdf..f0b4c334 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -18,6 +18,7 @@
+
@@ -25,19 +26,22 @@
+
+
-
+
+
@@ -51,9 +55,14 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
index 719ab113..34dbeb36 100644
--- a/.idea/encodings.xml
+++ b/.idea/encodings.xml
@@ -41,7 +41,15 @@
+
+
+
+
+
+
+
+
@@ -56,9 +64,9 @@
-
-
-
+
+
+
@@ -67,6 +75,14 @@
+
+
+
+
+
+
+
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 458b082b..8e3eb99c 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -20,11 +20,16 @@
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 97349d16..bbdb41e4 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -12,11 +12,9 @@
-
-
diff --git a/interconnect/README.md b/interconnect/README.md
index caee2000..ce0ad3de 100644
--- a/interconnect/README.md
+++ b/interconnect/README.md
@@ -1,3 +1,10 @@
## interconnect
+Interconnect enables service communication with objects implementing the interface `InterconnectObject`.
-*coming*
+interconnect needs `dvalin-jms` for service communication.
+
+* The `@Daemon` annotation is used with interfaces that extend `IDaemon` to provide information that clients can interact with that daemon.
+* `@Interconnect`
+
+### interconnect-core-legacy
+The projects `interconnect-core-legacy` provide legacy implementation. Relys on `interconnect-core-legacy-exceptions` and `dvalin-jms`
\ No newline at end of file
diff --git a/interconnect/core-legacy/pom.xml b/interconnect/core-legacy/pom.xml
new file mode 100644
index 00000000..bfc8be09
--- /dev/null
+++ b/interconnect/core-legacy/pom.xml
@@ -0,0 +1,116 @@
+
+ 4.0.0
+
+ de.taimos
+ dvalin-interconnect-parent
+ 1.36-SNAPSHOT
+
+ dvalin-interconnect-core-legacy
+ (Legacy) Dvalin interconnect core library
+
+
+
+
+ de.taimos
+ dvalin-daemon
+ ${project.version}
+
+
+ de.taimos
+ dvalin-interconnect-model
+ ${project.version}
+
+
+
+ org.apache.activemq
+ activemq-pool
+ ${activemq.version}
+
+
+ org.apache.activemq
+ activemq-client
+ ${activemq.version}
+
+
+
+
+
+ org.springframework
+ spring-core
+ ${org.springframework.version}
+
+
+
+
+ org.springframework
+ spring-expression
+ ${org.springframework.version}
+
+
+
+
+ org.springframework
+ spring-jms
+ ${org.springframework.version}
+
+
+
+
+ org.springframework
+ spring-beans
+ ${org.springframework.version}
+
+
+
+ org.springframework
+ spring-aop
+ ${org.springframework.version}
+
+
+
+
+ org.springframework
+ spring-context
+ ${org.springframework.version}
+
+
+
+
+ org.springframework
+ spring-context-support
+ ${org.springframework.version}
+
+
+
+
+ org.springframework
+ spring-tx
+ ${org.springframework.version}
+
+
+
+
+ org.springframework
+ spring-test
+ ${org.springframework.version}
+ test
+
+
+ javax.jms
+ javax.jms-api
+ 2.0.1
+ compile
+
+
+
diff --git a/interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorBurstTest.java b/interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorBurstTest.java
similarity index 93%
rename from interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorBurstTest.java
rename to interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorBurstTest.java
index 6c74cb17..5d7d2ee9 100644
--- a/interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorBurstTest.java
+++ b/interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorBurstTest.java
@@ -41,7 +41,7 @@ public final class InterconnectConnectorBurstTest implements Runnable {
* @throws Exception If ...
*/
public static void main(String[] args) throws Exception {
- de.taimos.dvalin.interconnect.core.TestHelper.initBrokerEnv("failover:tcp://localhost:61616");
+ TestHelper.initBrokerEnv("failover:tcp://localhost:61616");
try {
System.out.println("begin");
for (int i = 0; i < InterconnectConnectorBurstTest.THREADS; i++) {
@@ -54,7 +54,7 @@ public static void main(String[] args) throws Exception {
System.out.println("end");
System.out.println("duration: " + ((end - begin) / 1000L / 1000L) + " ms");
} finally {
- de.taimos.dvalin.interconnect.core.TestHelper.closeBrokerEnv();
+ TestHelper.closeBrokerEnv();
}
}
diff --git a/interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorITTest.java b/interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorITTest.java
similarity index 69%
rename from interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorITTest.java
rename to interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorITTest.java
index 7cf988a2..28175b36 100644
--- a/interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorITTest.java
+++ b/interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/InterconnectConnectorITTest.java
@@ -78,16 +78,16 @@ public void close() {
void testSimpleRequest() throws Exception {
final String q = this.queueName;
new Thread(() -> {
- try {
- final Response request = InterconnectConnector.receiveFromQueueEnhanced(q, "", 5000, false);
- Assertions.assertNotNull(request.getJMSTextMessage().getStringProperty(InterconnectConnector.HEADER_REQUEST_UUID));
- Assertions.assertNotNull(request.getJMSTextMessage().getStringProperty(InterconnectConnector.HEADER_ICO_CLASS));
- Assertions.assertEquals(VoidIVO.class, request.getICO().getClass());
- MessageConnector.sendToDestination(request.getJMSTextMessage().getJMSReplyTo(), InterconnectMapper.toJson(new VoidIVOBuilder().build()), new HashMap(), false, null, request.getJMSTextMessage().getJMSCorrelationID());
- } catch (final Exception e) {
- Assertions.fail("Exception");
- }
- }).start();
+ try {
+ final Response request = InterconnectConnector.receiveFromQueueEnhanced(q, "", 5000, false);
+ Assertions.assertNotNull(request.getJMSTextMessage().getStringProperty(InterconnectConnector.HEADER_REQUEST_UUID));
+ Assertions.assertNotNull(request.getJMSTextMessage().getStringProperty(InterconnectConnector.HEADER_ICO_CLASS));
+ Assertions.assertEquals(VoidIVO.class, request.getICO().getClass());
+ MessageConnector.sendToDestination(request.getJMSTextMessage().getJMSReplyTo(), InterconnectMapper.toJson(new VoidIVOBuilder().build()), new HashMap(), false, null, request.getJMSTextMessage().getJMSCorrelationID());
+ } catch (final Exception e) {
+ Assertions.fail("Exception");
+ }
+ }).start();
final InterconnectObject res = InterconnectConnector.request(UUID.randomUUID(), q, new VoidIVOBuilder().build(), new HashMap());
Assertions.assertEquals(VoidIVO.class, res.getClass());
}
@@ -96,19 +96,19 @@ void testSimpleRequest() throws Exception {
void testEncryptedRequest() throws Exception {
final String q = this.queueName;
new Thread(() -> {
- try {
- final TextMessage tm = MessageConnector.receiveFromQueue(q, "", 5000, false);
- final String json = InterconnectMapper.toJson(new VoidIVOBuilder().build());
- Assertions.assertNotNull(tm.getStringProperty(InterconnectConnector.HEADER_REQUEST_UUID));
- Assertions.assertNotNull(tm.getStringProperty(InterconnectConnector.HEADER_ICO_CLASS));
- Assertions.assertNotEquals(json, tm.getText());
- MessageConnector.decryptMessage(tm);
- Assertions.assertEquals(json, tm.getText());
- MessageConnector.sendToDestination(tm.getJMSReplyTo(), json, new HashMap(), true, null, tm.getJMSCorrelationID());
- } catch (final Exception e) {
- Assertions.fail("Exception");
- }
- }).start();
+ try {
+ final TextMessage tm = MessageConnector.receiveFromQueue(q, "", 5000, false);
+ final String json = InterconnectMapper.toJson(new VoidIVOBuilder().build());
+ Assertions.assertNotNull(tm.getStringProperty(InterconnectConnector.HEADER_REQUEST_UUID));
+ Assertions.assertNotNull(tm.getStringProperty(InterconnectConnector.HEADER_ICO_CLASS));
+ Assertions.assertNotEquals(json, tm.getText());
+ MessageConnector.decryptMessage(tm);
+ Assertions.assertEquals(json, tm.getText());
+ MessageConnector.sendToDestination(tm.getJMSReplyTo(), json, new HashMap(), true, null, tm.getJMSCorrelationID());
+ } catch (final Exception e) {
+ Assertions.fail("Exception");
+ }
+ }).start();
final InterconnectObject res = InterconnectConnector.request(UUID.randomUUID(), q, new VoidIVOBuilder().build(), new HashMap(), true, MessageConnector.REQUEST_TIMEOUT, MessageConnector.REQUEST_TIMEOUT, MessageConnector.MSGPRIORITY);
Assertions.assertEquals(VoidIVO.class, res.getClass());
}
@@ -172,16 +172,16 @@ void testSecureSendAndReceiveWithCorrelationId() throws Exception {
void testReceiveBulkFromQueue5of5() throws Exception {
final String q = this.queueName;
new Thread(() -> {
- try {
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- } catch (final Exception e) {
- Assertions.fail("Exception");
- }
- }).start();
+ try {
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ } catch (final Exception e) {
+ Assertions.fail("Exception");
+ }
+ }).start();
Assertions.assertEquals(5, InterconnectConnector.receiveBulkFromQueue(q, null, 5, 1000, false).size());
}
@@ -189,12 +189,12 @@ void testReceiveBulkFromQueue5of5() throws Exception {
void testReceiveBulkFromQueue1of5() throws Exception {
final String q = this.queueName;
new Thread(() -> {
- try {
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- } catch (final Exception e) {
- Assertions.fail("Exception");
- }
- }).start();
+ try {
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ } catch (final Exception e) {
+ Assertions.fail("Exception");
+ }
+ }).start();
Assertions.assertEquals(1, InterconnectConnector.receiveBulkFromQueue(q, null, 5, 1000, false).size());
}
@@ -202,17 +202,17 @@ void testReceiveBulkFromQueue1of5() throws Exception {
void testReceiveBulkFromQueue5of6() throws Exception {
final String q = this.queueName;
new Thread(() -> {
- try {
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
- } catch (final Exception e) {
- Assertions.fail("Exception");
- }
- }).start();
+ try {
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ InterconnectConnector.sendToQueue(InterconnectConnectorITTest.this.queueName, new VoidIVOBuilder().build(), null);
+ } catch (final Exception e) {
+ Assertions.fail("Exception");
+ }
+ }).start();
Assertions.assertEquals(5, InterconnectConnector.receiveBulkFromQueue(q, null, 5, 1000, false).size());
Assertions.assertEquals(1, InterconnectConnector.receiveBulkFromQueue(q, null, 5, 1000, false).size());
}
diff --git a/interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/MessageConnectorITTest.java b/interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/MessageConnectorITTest.java
similarity index 99%
rename from interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/MessageConnectorITTest.java
rename to interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/MessageConnectorITTest.java
index f85859b4..0d35136c 100644
--- a/interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/MessageConnectorITTest.java
+++ b/interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/MessageConnectorITTest.java
@@ -108,7 +108,7 @@ public void run() {
@Test
public void testDefaultTimeoutRequest() throws Exception {
Assertions.assertThrows(TimeoutException.class, () -> Assertions.assertTimeout(Duration.ofMillis(11000), () ->
- MessageConnector.request(this.queueName, "ping", new HashMap<>())));
+ MessageConnector.request(this.queueName, "ping", new HashMap<>())));
}
@Test
diff --git a/interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/TestHelper.java b/interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/TestHelper.java
similarity index 100%
rename from interconnect/core/src/it/java/de/taimos/dvalin/interconnect/core/TestHelper.java
rename to interconnect/core-legacy/src/it/java/de/taimos/dvalin/interconnect/core/TestHelper.java
diff --git a/interconnect/core/src/it/resources/.gitkeep b/interconnect/core-legacy/src/it/resources/.gitkeep
similarity index 100%
rename from interconnect/core/src/it/resources/.gitkeep
rename to interconnect/core-legacy/src/it/resources/.gitkeep
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/ActiveMQPooledConnectionFactory.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/ActiveMQPooledConnectionFactory.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/ActiveMQPooledConnectionFactory.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/ActiveMQPooledConnectionFactory.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/DvalinConnectionFactory.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/DvalinConnectionFactory.java
similarity index 97%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/DvalinConnectionFactory.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/DvalinConnectionFactory.java
index ed16a976..95e7cc5b 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/DvalinConnectionFactory.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/DvalinConnectionFactory.java
@@ -1,10 +1,5 @@
package de.taimos.dvalin.interconnect.core;
-import javax.jms.Connection;
-import javax.jms.ConnectionFactory;
-import javax.jms.ExceptionListener;
-import javax.jms.JMSException;
-
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.ClientInternalExceptionListener;
import org.apache.activemq.transport.TransportListener;
@@ -12,6 +7,11 @@
import org.slf4j.LoggerFactory;
import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+
/**
* Copyright 2022 Cinovo AG
*
@@ -42,7 +42,8 @@ public class DvalinConnectionFactory implements ConnectionFactory {
public DvalinConnectionFactory() {
String brokerURL = System.getProperty(DvalinConnectionFactory.SYSPROP_IBROKERURL);
if (brokerURL == null) {
- DvalinConnectionFactory.LOGGER.warn("No " + DvalinConnectionFactory.SYSPROP_IBROKERURL + " configured, using tcp://localhost:61616.");
+ DvalinConnectionFactory.LOGGER.warn(
+ "No " + DvalinConnectionFactory.SYSPROP_IBROKERURL + " configured, using tcp://localhost:61616.");
brokerURL = "tcp://localhost:61616";
}
this.userName = System.getProperty(DvalinConnectionFactory.SYSPROP_USERNAME);
diff --git a/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/EventSender.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/EventSender.java
new file mode 100644
index 00000000..20160f11
--- /dev/null
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/EventSender.java
@@ -0,0 +1,87 @@
+package de.taimos.dvalin.interconnect.core;
+
+/*-
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 - 2017 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.interconnect.model.InterconnectMapper;
+import de.taimos.dvalin.interconnect.model.event.EventDomain;
+import de.taimos.dvalin.interconnect.model.event.IEvent;
+import org.springframework.core.annotation.AnnotationUtils;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+
+public class EventSender extends ToTopicSender {
+
+ private static final String PROP_DEFAULT_VIRTUAL_TOPIC_PREFIX = "VirtualTopic";
+
+ private static EventSender instance = new EventSender();
+
+ private String virtualTopicPrefix;
+
+ private EventSender() {
+ super();
+ this.virtualTopicPrefix = System.getProperty(MessageConnector.SYSPROP_VIRTUAL_TOPIC_PREFIX, EventSender.PROP_DEFAULT_VIRTUAL_TOPIC_PREFIX);
+ }
+
+ /**
+ * @return the singleton
+ */
+ public static EventSender getInstance() {
+ return EventSender.instance;
+ }
+
+
+ public void send(Serializable object, String topicName) {
+ if(object instanceof IEvent) {
+ this.send((IEvent) object);
+ } else {
+ super.send(object, topicName);
+ }
+ }
+
+ /**
+ * @param object the object
+ */
+ public void send(IEvent object) {
+ Annotation domainAnnotation = AnnotationUtils.findAnnotation(object.getClass(), EventDomain.class);
+ if(domainAnnotation == null) {
+ this.logger.error("The event {} has no domain annotation", object.getClass().getSimpleName());
+ return;
+ }
+ if(((EventDomain) domainAnnotation).value().isEmpty()) {
+ this.logger.error("The domainname for the event {} is empty", object.getClass().getSimpleName());
+ return;
+ }
+ super.send(object, this.virtualTopicPrefix + "." + ((EventDomain) domainAnnotation).value());
+ }
+
+ protected Message getMessage(Serializable object, Session session) throws JMSException, IOException {
+ if(object instanceof IEvent) {
+ String json = InterconnectMapper.toJson((IEvent) object);
+ return session.createTextMessage(json);
+ }
+ return session.createObjectMessage(object);
+ }
+}
diff --git a/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/IVORefreshSender.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/IVORefreshSender.java
new file mode 100644
index 00000000..a427d3b0
--- /dev/null
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/IVORefreshSender.java
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package de.taimos.dvalin.interconnect.core;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import java.io.Serializable;
+
+public class IVORefreshSender extends ToTopicSender {
+
+ private static IVORefreshSender instance = new IVORefreshSender();
+
+ private IVORefreshSender() {
+ super();
+ }
+
+ /**
+ * @return the singleton
+ */
+ public static IVORefreshSender getInstance() {
+ return IVORefreshSender.instance;
+ }
+
+ /**
+ * @param object the object
+ */
+ public void send(Serializable object) {
+ this.send(object, System.getProperty(MessageConnector.SYSPROP_UPDATE_TOPIC));
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/InterconnectConnector.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/InterconnectConnector.java
similarity index 93%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/InterconnectConnector.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/InterconnectConnector.java
index b26010e9..34c9c18b 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/InterconnectConnector.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/InterconnectConnector.java
@@ -36,7 +36,7 @@
import com.google.common.base.Preconditions;
import de.taimos.dvalin.interconnect.core.exceptions.InfrastructureException;
-import de.taimos.dvalin.interconnect.model.CryptoException;
+import de.taimos.dvalin.interconnect.core.exceptions.MessageCryptoException;
import de.taimos.dvalin.interconnect.model.InterconnectMapper;
import de.taimos.dvalin.interconnect.model.InterconnectObject;
@@ -54,11 +54,11 @@ public final class InterconnectConnector {
* name of the message header to specify interconnect ICO class
*/
public static final String HEADER_ICO_CLASS = "InterconnectICOClass";
-
+
private static final String INTERCONNECT_OBJECT_NULL_ERROR = "Interconnect Object was null";
private static final String QUEUE_NAME_NULL_ERROR = "Queue name was null";
private static final String TOPIC_NAME_NULL_ERROR = "Topic name was null";
-
+
/**
* Singleton.
*/
@@ -96,12 +96,12 @@ public static void stop() throws InfrastructureException {
* @param replyToQueueName Reply is send to this queue (or null)
* @param correlationId Correlation id (or null)
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static void sendToDestination(final Destination destination, final InterconnectObject ico, final Map customHeaders, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, CryptoException, IOException {
+ public static void sendToDestination(final Destination destination, final InterconnectObject ico, final Map customHeaders, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(destination, "Destination was null");
Preconditions.checkNotNull(ico, INTERCONNECT_OBJECT_NULL_ERROR);
final String body = InterconnectMapper.toJson(ico);
@@ -123,12 +123,12 @@ public static void sendToDestination(final Destination destination, final Interc
* @param replyToQueueName Reply is send to this queue (or null)
* @param correlationId Correlation id (or null)
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static void sendToQueue(final String queueName, final InterconnectObject ico, final Map customHeaders, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, CryptoException, IOException {
+ public static void sendToQueue(final String queueName, final InterconnectObject ico, final Map customHeaders, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(queueName, QUEUE_NAME_NULL_ERROR);
Preconditions.checkNotNull(ico, INTERCONNECT_OBJECT_NULL_ERROR);
final String body = InterconnectMapper.toJson(ico);
@@ -148,12 +148,12 @@ public static void sendToQueue(final String queueName, final InterconnectObject
* @param customHeaders Headers
* @param secure Enable secure transport?
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static void sendToQueue(final String queueName, final InterconnectObject ico, final Map customHeaders, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static void sendToQueue(final String queueName, final InterconnectObject ico, final Map customHeaders, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(queueName, QUEUE_NAME_NULL_ERROR);
Preconditions.checkNotNull(ico, INTERCONNECT_OBJECT_NULL_ERROR);
final String body = InterconnectMapper.toJson(ico);
@@ -235,12 +235,12 @@ public static void sendToQueue(final String queueName, final InterconnectObject
* @param customHeaders Headers
* @param secure Enable secure transport?
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static void sendToTopic(final String topicName, final InterconnectObject ico, final Map customHeaders, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static void sendToTopic(final String topicName, final InterconnectObject ico, final Map customHeaders, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(topicName, TOPIC_NAME_NULL_ERROR);
Preconditions.checkNotNull(ico, INTERCONNECT_OBJECT_NULL_ERROR);
final String body = InterconnectMapper.toJson(ico);
@@ -298,12 +298,12 @@ public static void sendToTopic(final String topicName, final InterconnectObject
* @param secure Enable secure transport?
* @return Interconnect Object
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static InterconnectObject receiveFromQueue(final String queueName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static InterconnectObject receiveFromQueue(final String queueName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(queueName, QUEUE_NAME_NULL_ERROR);
final TextMessage response = MessageConnector.receiveFromQueue(queueName, selector, timeout, secure);
try {
@@ -320,12 +320,12 @@ public static InterconnectObject receiveFromQueue(final String queueName, final
* @param secure Enable secure transport?
* @return Response
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static Response receiveFromQueueEnhanced(final String queueName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static Response receiveFromQueueEnhanced(final String queueName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(queueName, QUEUE_NAME_NULL_ERROR);
final TextMessage response = MessageConnector.receiveFromQueue(queueName, selector, timeout, secure);
try {
@@ -343,12 +343,12 @@ public static Response receiveFromQueueEnhanced(final String queueName, final St
* @param secure Enable secure transport?
* @return Interconnect Object
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static List receiveBulkFromQueue(final String queueName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static List receiveBulkFromQueue(final String queueName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(queueName, QUEUE_NAME_NULL_ERROR);
final List responses = MessageConnector.receiveBulkFromQueue(queueName, selector, maxSize, timeout, secure);
final List icos = new ArrayList<>(responses.size());
@@ -370,12 +370,12 @@ public static List receiveBulkFromQueue(final String queueNa
* @param secure Enable secure transport?
* @return Response
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static List receiveBulkFromQueueEnhanced(final String queueName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static List receiveBulkFromQueueEnhanced(final String queueName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(queueName, QUEUE_NAME_NULL_ERROR);
final List responses = MessageConnector.receiveBulkFromQueue(queueName, selector, maxSize, timeout, secure);
final List enhanceds = new ArrayList<>(responses.size());
@@ -396,12 +396,12 @@ public static List receiveBulkFromQueueEnhanced(final String queueName
* @param secure Enable secure transport?
* @return Interconnect Object
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static InterconnectObject receiveFromTopic(final String topicName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static InterconnectObject receiveFromTopic(final String topicName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(topicName, TOPIC_NAME_NULL_ERROR);
final TextMessage response = MessageConnector.receiveFromTopic(topicName, selector, timeout, secure);
try {
@@ -418,12 +418,12 @@ public static InterconnectObject receiveFromTopic(final String topicName, final
* @param secure Enable secure transport?
* @return Response
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static Response receiveFromTopicEnhanced(final String topicName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static Response receiveFromTopicEnhanced(final String topicName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(topicName, TOPIC_NAME_NULL_ERROR);
final TextMessage response = MessageConnector.receiveFromTopic(topicName, selector, timeout, secure);
try {
@@ -441,12 +441,12 @@ public static Response receiveFromTopicEnhanced(final String topicName, final St
* @param secure Enable secure transport?
* @return Interconnect Object
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static List receiveBulkFromTopic(final String topicName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static List receiveBulkFromTopic(final String topicName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(topicName, TOPIC_NAME_NULL_ERROR);
final List responses = MessageConnector.receiveBulkFromTopic(topicName, selector, maxSize, timeout, secure);
final List icos = new ArrayList<>(responses.size());
@@ -468,12 +468,12 @@ public static List receiveBulkFromTopic(final String topicNa
* @param secure Enable secure transport?
* @return Response
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static List receiveBulkFromTopicEnhanced(final String topicName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, CryptoException, IOException {
+ public static List receiveBulkFromTopicEnhanced(final String topicName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(topicName, TOPIC_NAME_NULL_ERROR);
final List responses = MessageConnector.receiveBulkFromTopic(topicName, selector, maxSize, timeout, secure);
final List enhanceds = new ArrayList<>(responses.size());
@@ -536,12 +536,12 @@ public TextMessage getJMSTextMessage() {
* @param priority JMS priority
* @return Response Interconnect Object
* @throws InfrastructureException If an infrastructure error occurs
- * @throws CryptoException If the message could not be encrypted
+ * @throws MessageCryptoException If the message could not be encrypted
* @throws JsonGenerationException if the JSON data could not be generated
* @throws JsonMappingException if the object could not be mapped to a JSON string
* @throws IOException if an I/O related problem occurred
*/
- public static InterconnectObject request(final UUID uuid, final String queueName, final InterconnectObject requestICO, final Map customHeaders, final boolean secure, final long receiveTimeout, final long sendTimeout, final int priority) throws InfrastructureException, CryptoException, IOException {
+ public static InterconnectObject request(final UUID uuid, final String queueName, final InterconnectObject requestICO, final Map customHeaders, final boolean secure, final long receiveTimeout, final long sendTimeout, final int priority) throws InfrastructureException, MessageCryptoException, IOException {
Preconditions.checkNotNull(uuid, "Universally unique identifier of the request");
Preconditions.checkNotNull(queueName, QUEUE_NAME_NULL_ERROR);
Preconditions.checkNotNull(requestICO, "Request Interconnect Object");
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/MessageConnector.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/MessageConnector.java
similarity index 88%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/MessageConnector.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/MessageConnector.java
index d0847a31..2c5a485c 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/MessageConnector.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/MessageConnector.java
@@ -20,13 +20,15 @@
* #L%
*/
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicBoolean;
+import de.taimos.dvalin.interconnect.core.crypto.JmsMessageCryptoUtil;
+import de.taimos.dvalin.interconnect.core.exceptions.InfrastructureException;
+import de.taimos.dvalin.interconnect.core.exceptions.MessageCryptoException;
+import de.taimos.dvalin.interconnect.core.exceptions.SerializationException;
+import de.taimos.dvalin.interconnect.core.exceptions.TimeoutException;
+import org.apache.activemq.command.ActiveMQTextMessage;
+import org.apache.activemq.pool.PooledConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
@@ -40,16 +42,13 @@
import javax.jms.Session;
import javax.jms.TemporaryQueue;
import javax.jms.TextMessage;
-
-import de.taimos.dvalin.interconnect.core.exceptions.InfrastructureException;
-import de.taimos.dvalin.interconnect.core.exceptions.SerializationException;
-import de.taimos.dvalin.interconnect.core.exceptions.TimeoutException;
-import de.taimos.dvalin.interconnect.model.CryptoException;
-import de.taimos.dvalin.interconnect.model.MessageCryptoUtil;
-import org.apache.activemq.command.ActiveMQTextMessage;
-import org.apache.activemq.pool.PooledConnectionFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Connector to connect to JMS providers.
@@ -125,7 +124,8 @@ public static void start(final String brokerUrl) throws InfrastructureException
if (MessageConnector.started.compareAndSet(false, true)) {
DvalinConnectionFactory dvalinConnectionFactory = new DvalinConnectionFactory(brokerUrl);
dvalinConnectionFactory.setExceptionListener(MessageConnector.createMqErrorListener());
- MessageConnector.pooledConnectionFactory = new ActiveMQPooledConnectionFactory().initDefault(dvalinConnectionFactory);
+ MessageConnector.pooledConnectionFactory = new ActiveMQPooledConnectionFactory().initDefault(
+ dvalinConnectionFactory);
}
}
@@ -137,9 +137,11 @@ public static void start(final String brokerUrl) throws InfrastructureException
*/
public static void start(final String brokerUrl, final String userName, final String password) throws InfrastructureException {
if (MessageConnector.started.compareAndSet(false, true)) {
- DvalinConnectionFactory dvalinConnectionFactory = new DvalinConnectionFactory(brokerUrl, userName, password);
+ DvalinConnectionFactory dvalinConnectionFactory = new DvalinConnectionFactory(brokerUrl, userName,
+ password);
dvalinConnectionFactory.setExceptionListener(MessageConnector.createMqErrorListener());
- MessageConnector.pooledConnectionFactory = new ActiveMQPooledConnectionFactory().initDefault(dvalinConnectionFactory);
+ MessageConnector.pooledConnectionFactory = new ActiveMQPooledConnectionFactory().initDefault(
+ dvalinConnectionFactory);
}
}
@@ -204,7 +206,7 @@ public Destination get(final Session session) throws JMSException {
}
- private static void sendToDestination(final GetDestinationAction getDestinationAction, final String body, final Map headers, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, CryptoException {
+ private static void sendToDestination(final GetDestinationAction getDestinationAction, final String body, final Map headers, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, MessageCryptoException {
MessageConnector.checkInit();
Connection connection = null;
@@ -297,10 +299,11 @@ private static void sendToDestination(final GetDestinationAction getDestinationA
* @param replyToQueueName the name of the queue to reply to or null
* @param correlationId the correlated id
* @throws InfrastructureException on errors
- * @throws CryptoException on secure transport errors
+ * @throws MessageCryptoException on secure transport errors
*/
- private static void sendToDestination(final boolean isQueue, final String destinationName, final String body, final Map headers, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, CryptoException {
- MessageConnector.sendToDestination(new GetResolveDestinationAction(isQueue, destinationName), body, headers, secure, replyToQueueName, correlationId);
+ private static void sendToDestination(final boolean isQueue, final String destinationName, final String body, final Map headers, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, MessageCryptoException {
+ MessageConnector.sendToDestination(new GetResolveDestinationAction(isQueue, destinationName), body, headers,
+ secure, replyToQueueName, correlationId);
}
/**
@@ -311,10 +314,11 @@ private static void sendToDestination(final boolean isQueue, final String destin
* @param replyToQueueName the name of the queue to reply to or null
* @param correlationId the correlated id
* @throws InfrastructureException on errors
- * @throws CryptoException on secure transport errors
+ * @throws MessageCryptoException on secure transport errors
*/
- public static void sendToDestination(final Destination destination, final String body, final Map headers, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, CryptoException {
- MessageConnector.sendToDestination(new GetSimpleDestinationAction(destination), body, headers, secure, replyToQueueName, correlationId);
+ public static void sendToDestination(final Destination destination, final String body, final Map headers, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, MessageCryptoException {
+ MessageConnector.sendToDestination(new GetSimpleDestinationAction(destination), body, headers, secure,
+ replyToQueueName, correlationId);
}
/**
@@ -325,9 +329,9 @@ public static void sendToDestination(final Destination destination, final String
* @param replyToQueueName the name of the queue to reply to or null
* @param correlationId the correlated id
* @throws InfrastructureException on errors
- * @throws CryptoException on secure transport errors
+ * @throws MessageCryptoException on secure transport errors
*/
- public static void sendToQueue(final String queueName, final String body, final Map headers, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, CryptoException {
+ public static void sendToQueue(final String queueName, final String body, final Map headers, final boolean secure, final String replyToQueueName, final String correlationId) throws InfrastructureException, MessageCryptoException {
MessageConnector.sendToDestination(true, queueName, body, headers, secure, replyToQueueName, correlationId);
}
@@ -337,9 +341,9 @@ public static void sendToQueue(final String queueName, final String body, final
* @param headers the request headers
* @param secure enable secure transport
* @throws InfrastructureException on errors
- * @throws CryptoException on secure transport errors
+ * @throws MessageCryptoException on secure transport errors
*/
- public static void sendToQueue(final String queueName, final String body, final Map headers, final boolean secure) throws InfrastructureException, CryptoException {
+ public static void sendToQueue(final String queueName, final String body, final Map headers, final boolean secure) throws InfrastructureException, MessageCryptoException {
MessageConnector.sendToQueue(queueName, body, headers, secure, null, null);
}
@@ -354,8 +358,8 @@ public static void sendToQueue(final String queueName, final String body, final
public static void sendToQueue(final String queueName, final String body, final Map headers, final String replyToQueueName, final String correlationId) throws InfrastructureException {
try {
MessageConnector.sendToQueue(queueName, body, headers, false, replyToQueueName, correlationId);
- } catch (final CryptoException e) {
- // secure is false --> No CryptoException
+ } catch (final MessageCryptoException e) {
+ // secure is false --> No MessageCryptoException
}
}
@@ -368,8 +372,8 @@ public static void sendToQueue(final String queueName, final String body, final
public static void sendToQueue(final String queueName, final String body, final Map headers) throws InfrastructureException {
try {
MessageConnector.sendToQueue(queueName, body, headers, false);
- } catch (final CryptoException e) {
- // secure is false --> No CryptoException
+ } catch (final MessageCryptoException e) {
+ // secure is false --> No MessageCryptoException
}
}
@@ -379,9 +383,9 @@ public static void sendToQueue(final String queueName, final String body, final
* @param headers the request headers
* @param secure enable secure transport
* @throws InfrastructureException on errors
- * @throws CryptoException on secure transport errors
+ * @throws MessageCryptoException on secure transport errors
*/
- public static void sendToTopic(final String topicName, final String body, final Map headers, final boolean secure) throws InfrastructureException, CryptoException {
+ public static void sendToTopic(final String topicName, final String body, final Map headers, final boolean secure) throws InfrastructureException, MessageCryptoException {
MessageConnector.sendToDestination(false, topicName, body, headers, secure, null, null);
}
@@ -394,8 +398,8 @@ public static void sendToTopic(final String topicName, final String body, final
public static void sendToTopic(final String topicName, final String body, final Map headers) throws InfrastructureException {
try {
MessageConnector.sendToTopic(topicName, body, headers, false);
- } catch (final CryptoException e) {
- // secure is false --> No CryptoException
+ } catch (final MessageCryptoException e) {
+ // secure is false --> No MessageCryptoException
}
}
@@ -406,15 +410,15 @@ public static void sendToTopic(final String topicName, final String body, final
* @param secure enable secure transport
* @return the received {@link TextMessage}
* @throws InfrastructureException on errors
- * @throws CryptoException on crypto errors
+ * @throws MessageCryptoException on crypto errors
* @deprecated use receiveFromQueue instead
*/
@Deprecated
- public static TextMessage receive(final String queueName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, CryptoException {
+ public static TextMessage receive(final String queueName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException {
return MessageConnector.receiveFromQueue(queueName, selector, timeout, secure);
}
- private static List receiveBulkFromDestination(final GetDestinationAction getDestinationAction, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, CryptoException {
+ private static List receiveBulkFromDestination(final GetDestinationAction getDestinationAction, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException {
MessageConnector.checkInit();
final List messages = new ArrayList<>(maxSize);
@@ -501,8 +505,9 @@ private static List receiveBulkFromDestination(final GetDestination
}
}
- private static TextMessage receiveFromDestination(final GetDestinationAction getDestinationAction, final String selector, final long timeout, final boolean secure) throws InfrastructureException, CryptoException {
- final List messages = MessageConnector.receiveBulkFromDestination(getDestinationAction, selector, 1, timeout, secure);
+ private static TextMessage receiveFromDestination(final GetDestinationAction getDestinationAction, final String selector, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException {
+ final List messages = MessageConnector.receiveBulkFromDestination(getDestinationAction, selector,
+ 1, timeout, secure);
if (messages.size() != 1) {
throw new InfrastructureException(MessageConnector.RECEIVE_FAILED);
}
@@ -516,10 +521,11 @@ private static TextMessage receiveFromDestination(final GetDestinationAction get
* @param secure enable secure transport
* @return the received {@link TextMessage}
* @throws InfrastructureException on errors
- * @throws CryptoException on crypto errors
+ * @throws MessageCryptoException on crypto errors
*/
- public static TextMessage receiveFromQueue(final String queueName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, CryptoException {
- return MessageConnector.receiveFromDestination(new GetResolveDestinationAction(true, queueName), selector, timeout, secure);
+ public static TextMessage receiveFromQueue(final String queueName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException {
+ return MessageConnector.receiveFromDestination(new GetResolveDestinationAction(true, queueName), selector,
+ timeout, secure);
}
/**
@@ -530,10 +536,11 @@ public static TextMessage receiveFromQueue(final String queueName, final String
* @param secure enable secure transport
* @return the received {@link TextMessage}s
* @throws InfrastructureException on errors
- * @throws CryptoException on crypto errors
+ * @throws MessageCryptoException on crypto errors
*/
- public static List receiveBulkFromQueue(final String queueName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, CryptoException {
- return MessageConnector.receiveBulkFromDestination(new GetResolveDestinationAction(true, queueName), selector, maxSize, timeout, secure);
+ public static List receiveBulkFromQueue(final String queueName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException {
+ return MessageConnector.receiveBulkFromDestination(new GetResolveDestinationAction(true, queueName), selector,
+ maxSize, timeout, secure);
}
/**
@@ -543,10 +550,11 @@ public static List receiveBulkFromQueue(final String queueName, fin
* @param secure enable secure transport
* @return the received {@link TextMessage}
* @throws InfrastructureException on errors
- * @throws CryptoException on crypto errors
+ * @throws MessageCryptoException on crypto errors
*/
- public static TextMessage receiveFromTopic(final String topicName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, CryptoException {
- return MessageConnector.receiveFromDestination(new GetResolveDestinationAction(false, topicName), selector, timeout, secure);
+ public static TextMessage receiveFromTopic(final String topicName, final String selector, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException {
+ return MessageConnector.receiveFromDestination(new GetResolveDestinationAction(false, topicName), selector,
+ timeout, secure);
}
/**
@@ -557,10 +565,11 @@ public static TextMessage receiveFromTopic(final String topicName, final String
* @param secure enable secure transport
* @return the received {@link TextMessage}s
* @throws InfrastructureException on errors
- * @throws CryptoException on crypto errors
+ * @throws MessageCryptoException on crypto errors
*/
- public static List receiveBulkFromTopic(final String topicName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, CryptoException {
- return MessageConnector.receiveBulkFromDestination(new GetResolveDestinationAction(false, topicName), selector, maxSize, timeout, secure);
+ public static List receiveBulkFromTopic(final String topicName, final String selector, final int maxSize, final long timeout, final boolean secure) throws InfrastructureException, MessageCryptoException {
+ return MessageConnector.receiveBulkFromDestination(new GetResolveDestinationAction(false, topicName), selector,
+ maxSize, timeout, secure);
}
/**
@@ -573,9 +582,9 @@ public static List receiveBulkFromTopic(final String topicName, fin
* @param priority the message priority
* @return the response {@link TextMessage}
* @throws InfrastructureException on errors
- * @throws CryptoException on secure transport errors
+ * @throws MessageCryptoException on secure transport errors
*/
- public static TextMessage request(final String queueName, final String body, final Map headers, final boolean secure, final long receiveTimeout, final long sendTimeout, final int priority) throws InfrastructureException, CryptoException {
+ public static TextMessage request(final String queueName, final String body, final Map headers, final boolean secure, final long receiveTimeout, final long sendTimeout, final int priority) throws InfrastructureException, MessageCryptoException {
MessageConnector.checkInit();
final String correlationId = UUID.randomUUID().toString();
@@ -692,22 +701,23 @@ public static TextMessage request(final String queueName, final String body, fin
*/
public static TextMessage request(final String queueName, final String body, final Map headers) throws InfrastructureException {
try {
- return MessageConnector.request(queueName, body, headers, false, MessageConnector.REQUEST_TIMEOUT, MessageConnector.REQUEST_TIMEOUT, MessageConnector.MSGPRIORITY);
- } catch (final CryptoException e) {
- // secure is false --> No CryptoException
+ return MessageConnector.request(queueName, body, headers, false, MessageConnector.REQUEST_TIMEOUT,
+ MessageConnector.REQUEST_TIMEOUT, MessageConnector.MSGPRIORITY);
+ } catch (final MessageCryptoException e) {
+ // secure is false --> No MessageCryptoException
}
return null;
}
/**
* @param txt the message to encrypt
- * @throws CryptoException on crypto errors
- * @throws InfrastructureException on infrastructure exception
* @return if message is secure
+ * @throws MessageCryptoException on crypto errors
+ * @throws InfrastructureException on infrastructure exception
*/
- public static boolean isMessageSecure(final TextMessage txt) throws CryptoException, InfrastructureException {
+ public static boolean isMessageSecure(final TextMessage txt) throws MessageCryptoException, InfrastructureException {
try {
- return txt.propertyExists(MessageCryptoUtil.SIGNATURE_HEADER);
+ return txt.propertyExists(JmsMessageCryptoUtil.SIGNATURE_HEADER);
} catch (JMSException e) {
throw new InfrastructureException(MessageConnector.SECURITY_CHECK_FAILED, e);
}
@@ -715,39 +725,39 @@ public static boolean isMessageSecure(final TextMessage txt) throws CryptoExcept
/**
* @param txt the message to encrypt
- * @throws CryptoException on crypto errors
+ * @throws MessageCryptoException on crypto errors
*/
- public static void decryptMessage(final TextMessage txt) throws CryptoException {
+ public static void decryptMessage(final TextMessage txt) throws MessageCryptoException {
try {
- if (!txt.propertyExists(MessageCryptoUtil.SIGNATURE_HEADER)) {
- throw new CryptoException(MessageConnector.SECURITY_CHECK_FAILED);
+ if (!txt.propertyExists(JmsMessageCryptoUtil.SIGNATURE_HEADER)) {
+ throw new MessageCryptoException(MessageConnector.SECURITY_CHECK_FAILED);
}
- final String signature = txt.getStringProperty(MessageCryptoUtil.SIGNATURE_HEADER);
- final boolean validate = MessageCryptoUtil.validate(txt.getText(), signature);
+ final String signature = txt.getStringProperty(JmsMessageCryptoUtil.SIGNATURE_HEADER);
+ final boolean validate = JmsMessageCryptoUtil.validate(txt.getText(), signature);
if (!validate) {
- throw new CryptoException(MessageConnector.SECURITY_CHECK_FAILED);
+ throw new MessageCryptoException(MessageConnector.SECURITY_CHECK_FAILED);
}
if (txt instanceof ActiveMQTextMessage) {
final ActiveMQTextMessage t = (ActiveMQTextMessage) txt;
t.setReadOnlyBody(false);
}
- final String decryptedText = MessageCryptoUtil.decrypt(txt.getText());
+ final String decryptedText = JmsMessageCryptoUtil.decrypt(txt.getText());
txt.setText(decryptedText);
} catch (final JMSException e) {
- throw new CryptoException(MessageConnector.SECURITY_CHECK_FAILED, e);
+ throw new MessageCryptoException(MessageConnector.SECURITY_CHECK_FAILED, e);
}
}
/**
* @param txt the message to encrypt
- * @throws JMSException on JMS errors
- * @throws CryptoException on crypto errors
+ * @throws JMSException on JMS errors
+ * @throws MessageCryptoException on crypto errors
*/
- public static void secureMessage(final TextMessage txt) throws JMSException, CryptoException {
- final String cryptedText = MessageCryptoUtil.crypt(txt.getText());
+ public static void secureMessage(final TextMessage txt) throws JMSException, MessageCryptoException {
+ final String cryptedText = JmsMessageCryptoUtil.crypt(txt.getText());
txt.setText(cryptedText);
- txt.setStringProperty(MessageCryptoUtil.SIGNATURE_HEADER, MessageCryptoUtil.sign(cryptedText));
+ txt.setStringProperty(JmsMessageCryptoUtil.SIGNATURE_HEADER, JmsMessageCryptoUtil.sign(cryptedText));
}
private static void checkInit() throws InfrastructureException {
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/ToTopicSender.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/ToTopicSender.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/ToTopicSender.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/ToTopicSender.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/config/JMSConfig.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/config/JMSConfig.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/config/JMSConfig.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/config/JMSConfig.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/config/MultiRequestHandlerConfig.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/config/MultiRequestHandlerConfig.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/config/MultiRequestHandlerConfig.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/config/MultiRequestHandlerConfig.java
diff --git a/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/crypto/ACryptoService.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/crypto/ACryptoService.java
new file mode 100644
index 00000000..be8701d9
--- /dev/null
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/crypto/ACryptoService.java
@@ -0,0 +1,54 @@
+package de.taimos.dvalin.interconnect.core.crypto;
+
+
+import de.taimos.dvalin.interconnect.core.exceptions.MessageCryptoException;
+
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public abstract class ACryptoService implements ICryptoService {
+
+
+ @Override
+ public boolean isMessageSecure(final TextMessage txt) throws MessageCryptoException {
+ try {
+ return txt.propertyExists(JmsMessageCryptoUtil.SIGNATURE_HEADER);
+ } catch (JMSException e) {
+ throw new MessageCryptoException(e);
+ }
+ }
+
+ @Override
+ public TextMessage secureMessage(final TextMessage txt) throws JMSException, MessageCryptoException {
+ final String cryptedText = JmsMessageCryptoUtil.crypt(txt.getText());
+ txt.setText(cryptedText);
+ txt.setStringProperty(JmsMessageCryptoUtil.SIGNATURE_HEADER, JmsMessageCryptoUtil.sign(cryptedText));
+ return txt;
+ }
+
+ @Override
+ public TextMessage decryptMessage(TextMessage txt) throws MessageCryptoException {
+ try {
+ if (!txt.propertyExists(JmsMessageCryptoUtil.SIGNATURE_HEADER)) {
+ throw new MessageCryptoException();
+ }
+ final String signature = txt.getStringProperty(JmsMessageCryptoUtil.SIGNATURE_HEADER);
+ final boolean validate = JmsMessageCryptoUtil.validate(txt.getText(), signature);
+ if (!validate) {
+ throw new MessageCryptoException();
+ }
+
+ final String decryptedText = JmsMessageCryptoUtil.decrypt(txt.getText());
+ txt.setText(decryptedText);
+ } catch (final JMSException e) {
+ throw new MessageCryptoException(e);
+ }
+ return txt;
+ }
+}
diff --git a/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/crypto/ICryptoService.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/crypto/ICryptoService.java
new file mode 100644
index 00000000..0d36be6b
--- /dev/null
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/crypto/ICryptoService.java
@@ -0,0 +1,39 @@
+package de.taimos.dvalin.interconnect.core.crypto;
+
+import de.taimos.dvalin.interconnect.core.exceptions.InfrastructureException;
+import de.taimos.dvalin.interconnect.core.exceptions.MessageCryptoException;
+
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public interface ICryptoService {
+
+ /**
+ * @param txt the message to encrypt
+ * @return if message is secure
+ * @throws MessageCryptoException on crypto errors
+ * @throws InfrastructureException on infrastructure exception
+ */
+ boolean isMessageSecure(final TextMessage txt) throws MessageCryptoException, InfrastructureException, MessageCryptoException;
+
+ /**
+ * @param txt the message to encrypt
+ * @return the decrypted text message
+ * @throws MessageCryptoException on crypto errors
+ */
+ TextMessage decryptMessage(final TextMessage txt) throws MessageCryptoException;
+
+ /**
+ * @param txt the message to encrypt
+ * @return the secured text message
+ * @throws JMSException on JMS errors
+ * @throws MessageCryptoException on crypto errors
+ */
+ TextMessage secureMessage(final TextMessage txt) throws JMSException, MessageCryptoException;
+}
diff --git a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/MessageCryptoUtil.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/crypto/JmsMessageCryptoUtil.java
similarity index 72%
rename from interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/MessageCryptoUtil.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/crypto/JmsMessageCryptoUtil.java
index fc7158ee..4caab02a 100644
--- a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/MessageCryptoUtil.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/crypto/JmsMessageCryptoUtil.java
@@ -1,4 +1,4 @@
-package de.taimos.dvalin.interconnect.model;
+package de.taimos.dvalin.interconnect.core.crypto;
/*
* #%L
@@ -20,6 +20,15 @@
* #L%
*/
+import de.taimos.dvalin.interconnect.core.exceptions.MessageCryptoException;
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -31,18 +40,16 @@
import java.security.spec.AlgorithmParameterSpec;
import java.util.Scanner;
-import javax.crypto.Cipher;
-import javax.crypto.KeyGenerator;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.GCMParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
+public final class JmsMessageCryptoUtil {
-import org.apache.commons.codec.binary.Base64;
-public final class MessageCryptoUtil {
+ /** Constant for the system property that holds the AES key for message encryption */
+ public static final String PROPERTY_CRYPTO_AESKEY = "interconnect.crypto.aes";
+
+ /** Constant for the system property that holds the Signature key for message encryption */
+ public static final String PROPERTY_CRYPTO_SIGNATURE = "interconnect.crypto.signature";
- private MessageCryptoUtil() {
+ private JmsMessageCryptoUtil() {
// Utility class with private constructor
}
@@ -53,16 +60,16 @@ private MessageCryptoUtil() {
public static final String SIGNATURE_HEADER = "Signature";
// DO NEVER EVER CHANGE THIS; MESSAGES ARE NOT RECOVERABLE AFTER CHANGE
- private static final String AES_KEY = System.getProperty(InterconnectConstants.PROPERTY_CRYPTO_AESKEY);
- private static final String SIGNATURE = System.getProperty(InterconnectConstants.PROPERTY_CRYPTO_SIGNATURE);
+ private static final String AES_KEY = System.getProperty(JmsMessageCryptoUtil.PROPERTY_CRYPTO_AESKEY);
+ private static final String SIGNATURE = System.getProperty(JmsMessageCryptoUtil.PROPERTY_CRYPTO_SIGNATURE);
/**
* @param data the data to encrypt
* @return the encrypted BASE64 data
- * @throws CryptoException on encryption error
+ * @throws MessageCryptoException on encryption error
*/
- public static String crypt(final String data) throws CryptoException {
+ public static String crypt(final String data) throws MessageCryptoException {
if (data == null) {
return null;
}
@@ -71,7 +78,7 @@ public static String crypt(final String data) throws CryptoException {
byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(iv);
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
- final Cipher cipher = MessageCryptoUtil.getCipher(Cipher.ENCRYPT_MODE, parameterSpec);
+ final Cipher cipher = JmsMessageCryptoUtil.getCipher(Cipher.ENCRYPT_MODE, parameterSpec);
final byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + encrypted.length);
@@ -80,31 +87,31 @@ public static String crypt(final String data) throws CryptoException {
byte[] cipherMessage = byteBuffer.array();
return Base64.encodeBase64String(cipherMessage);
} catch (final Exception e) {
- throw new CryptoException("Encryption of data failed!", e);
+ throw new MessageCryptoException("Encryption of data failed!", e);
}
}
/**
* @param data the BASE 64 data
* @return the decrypted data
- * @throws CryptoException on decryption error
+ * @throws MessageCryptoException on decryption error
*/
- public static String decrypt(final String data) throws CryptoException {
+ public static String decrypt(final String data) throws MessageCryptoException {
if (data == null) {
return null;
}
try {
byte[] cipherMessage = Base64.decodeBase64(data);
AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, cipherMessage, 0, 12);
- final Cipher cipher = MessageCryptoUtil.getCipher(Cipher.DECRYPT_MODE, gcmIv);
+ final Cipher cipher = JmsMessageCryptoUtil.getCipher(Cipher.DECRYPT_MODE, gcmIv);
return new String(cipher.doFinal(cipherMessage, 12, cipherMessage.length - 12), StandardCharsets.UTF_8);
} catch (final Exception e) {
- throw new CryptoException("Decryption of data failed!", e);
+ throw new MessageCryptoException("Decryption of data failed!", e);
}
}
private static Cipher getCipher(int mode, AlgorithmParameterSpec gcmIv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
- final SecretKeySpec skeySpec = new SecretKeySpec(Base64.decodeBase64(MessageCryptoUtil.AES_KEY), "AES");
+ final SecretKeySpec skeySpec = new SecretKeySpec(Base64.decodeBase64(JmsMessageCryptoUtil.AES_KEY), "AES");
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(mode, skeySpec, gcmIv);
return cipher;
@@ -113,16 +120,16 @@ private static Cipher getCipher(int mode, AlgorithmParameterSpec gcmIv) throws N
/**
* @param msg the message to sign
* @return the signature hash
- * @throws CryptoException on sign error
+ * @throws MessageCryptoException on sign error
*/
- public static String sign(final String msg) throws CryptoException {
+ public static String sign(final String msg) throws MessageCryptoException {
try {
- final String toEnc = msg + MessageCryptoUtil.SIGNATURE;
+ final String toEnc = msg + JmsMessageCryptoUtil.SIGNATURE;
final MessageDigest mdEnc = MessageDigest.getInstance("MD5");
mdEnc.update(toEnc.getBytes(StandardCharsets.UTF_8), 0, toEnc.length());
return new BigInteger(1, mdEnc.digest()).toString(16);
} catch (final Exception e) {
- throw new CryptoException("Creating signature failed", e);
+ throw new MessageCryptoException("Creating signature failed", e);
}
}
@@ -130,13 +137,13 @@ public static String sign(final String msg) throws CryptoException {
* @param msg the message to validate
* @param signature the signature hash to check
* @return validation result
- * @throws CryptoException on sign error
+ * @throws MessageCryptoException on sign error
*/
- public static boolean validate(final String msg, final String signature) throws CryptoException {
+ public static boolean validate(final String msg, final String signature) throws MessageCryptoException {
if ((signature == null) || signature.isEmpty()) {
return false;
}
- final String calcSig = MessageCryptoUtil.sign(msg);
+ final String calcSig = JmsMessageCryptoUtil.sign(msg);
return calcSig.equals(signature);
}
@@ -160,17 +167,17 @@ public static void main(String[] args) {
}
switch (scan.nextLine()) {
case "k":
- MessageCryptoUtil.generateKey();
+ JmsMessageCryptoUtil.generateKey();
break;
case "c":
System.out.print("Input data: ");
final String data = scan.nextLine();
- System.out.println(MessageCryptoUtil.crypt(data));
+ System.out.println(JmsMessageCryptoUtil.crypt(data));
break;
case "d":
System.out.print("Input data: ");
final String ddata = scan.nextLine();
- System.out.println(MessageCryptoUtil.decrypt(ddata));
+ System.out.println(JmsMessageCryptoUtil.decrypt(ddata));
break;
default:
break;
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonMessageHandler.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonMessageHandler.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonMessageHandler.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonMessageHandler.java
index 286ed940..d1caaf7b 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonMessageHandler.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonMessageHandler.java
@@ -147,7 +147,7 @@ public final void onMessage(final Message message) throws Exception {
InterconnectContext.setDeliveryCount(deliveryCount);
InterconnectContext.setRedelivered(message.getJMSRedelivered());
- Class extends IVO> ivoClass = null;
+ Class extends IVO> ivoClass;
if (ivoIn instanceof IVO) {
ivoClass = (Class extends IVO>) ivoIn.getClass();
InterconnectContext.setRequestClass(ivoClass);
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonProxyFactory.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonProxyFactory.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonProxyFactory.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/ADaemonProxyFactory.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonMethodRegistry.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonMethodRegistry.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonMethodRegistry.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonMethodRegistry.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequest.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequest.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequest.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequest.java
index 2c793757..b7a7cc4b 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequest.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequest.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequestResponse.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequestResponse.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequestResponse.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequestResponse.java
index 098555fd..8b525a26 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequestResponse.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonRequestResponse.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonResponse.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonResponse.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonResponse.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonResponse.java
index 7a25e439..72363bd0 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonResponse.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/DaemonResponse.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonProxyFactory.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonProxyFactory.java
new file mode 100644
index 00000000..6c4ef75e
--- /dev/null
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonProxyFactory.java
@@ -0,0 +1,35 @@
+package de.taimos.dvalin.interconnect.core.daemon;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.interconnect.model.service.IDaemon;
+
+
+public interface IDaemonProxyFactory {
+
+ /**
+ * @param Daemon type
+ * @param daemon Daemon interface
+ * @return Proxy
+ */
+ D create(Class daemon);
+
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonRequestResponse.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonRequestResponse.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonRequestResponse.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonRequestResponse.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IdemponentRetryException.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IdemponentRetryException.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IdemponentRetryException.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IdemponentRetryException.java
index e22c27da..a8d0bdb2 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IdemponentRetryException.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IdemponentRetryException.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/Interconnect.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/Interconnect.java
new file mode 100644
index 00000000..504ae111
--- /dev/null
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/Interconnect.java
@@ -0,0 +1,34 @@
+package de.taimos.dvalin.interconnect.core.daemon;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD})
+public @interface Interconnect {
+
+ //
+
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/PagingController.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/PagingController.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/PagingController.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/daemon/PagingController.java
diff --git a/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/event/EventHandler.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/event/EventHandler.java
new file mode 100644
index 00000000..e3da3bdd
--- /dev/null
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/event/EventHandler.java
@@ -0,0 +1,21 @@
+package de.taimos.dvalin.interconnect.core.event;
+
+
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Component
+@Scope("prototype")
+public @interface EventHandler {
+ //
+}
diff --git a/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/event/EventMessageListener.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/event/EventMessageListener.java
new file mode 100644
index 00000000..8ee17387
--- /dev/null
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/event/EventMessageListener.java
@@ -0,0 +1,169 @@
+package de.taimos.dvalin.interconnect.core.event;
+
+/*-
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 - 2017 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.daemon.spring.annotations.ProdComponent;
+import de.taimos.dvalin.interconnect.core.MessageConnector;
+import de.taimos.dvalin.interconnect.model.InterconnectMapper;
+import de.taimos.dvalin.interconnect.model.InterconnectObject;
+import de.taimos.dvalin.interconnect.model.event.EventDomain;
+import de.taimos.dvalin.interconnect.model.event.IEvent;
+import de.taimos.dvalin.interconnect.model.service.IEventHandler;
+import org.apache.activemq.command.ActiveMQQueue;
+import org.apache.activemq.jms.pool.PooledConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.jms.listener.DefaultMessageListenerContainer;
+import org.springframework.jms.listener.MessageListenerContainer;
+import org.springframework.util.ErrorHandler;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.jms.ConnectionFactory;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+@ProdComponent("eventMessageListener")
+public class EventMessageListener implements MessageListener, ErrorHandler {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Value("${interconnect.jms.consumers:2-8}")
+ private String consumers;
+
+ @Value("${serviceName}")
+ private String serviceName;
+
+ @Value("${interconnect.jms.virtualtopic.prefix:VirtualTopic}")
+ private String virtualTopicPrefix;
+ @Value("${interconnect.jms.virtualtopic.consumerprefix:Consumer}")
+ private String consumerPrefix;
+
+ @Autowired
+ @Qualifier("DvalinConnectionFactory")
+ private ConnectionFactory jmsFactory;
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ private Set eventHandlers;
+ private Set listeners;
+
+ /** */
+ public EventMessageListener() {
+ super();
+ }
+
+ /** */
+ @PostConstruct
+ public void initEventListeners() {
+ this.listeners = new HashSet<>();
+ this.eventHandlers = new HashSet<>();
+ for(Object o : this.applicationContext.getBeansWithAnnotation(EventHandler.class).values()) {
+ if(o instanceof IEventHandler) {
+ this.eventHandlers.add((IEventHandler) o);
+ }
+ }
+
+ for(String domain : this.getDomains()) {
+ this.logger.info("Registered EventListener for topic {}", domain);
+ DefaultMessageListenerContainer dmlc = this.createQueueListener(domain);
+ this.listeners.add(dmlc);
+ }
+ }
+
+
+ /** */
+ @PreDestroy
+ public void stopEventListeners() {
+ for(MessageListenerContainer listener : this.listeners) {
+ listener.stop();
+ }
+ }
+
+ @Override
+ public void onMessage(Message message) {
+ try {
+ if(message instanceof TextMessage) {
+ final TextMessage textMessage = (TextMessage) message;
+ this.logger.debug("TextMessage received: {}", textMessage.getText());
+ final boolean secure = MessageConnector.isMessageSecure(textMessage);
+ if(secure) {
+ MessageConnector.decryptMessage(textMessage);
+ }
+ final InterconnectObject eventIn = InterconnectMapper.fromJson(textMessage.getText(), InterconnectObject.class);
+ for(IEventHandler eventHandler : this.eventHandlers) {
+ if(eventHandler != null && eventIn.getClass().isAssignableFrom(eventHandler.getEventType())) {
+ eventHandler.handleEvent((IEvent) eventIn);
+ }
+ }
+ }
+ } catch(final Exception e) {
+ // we are in non transactional wonderland so we catch the exception which leads to a request without a response.
+ this.logger.error("Exception", e);
+ }
+ }
+
+ @Override
+ public void handleError(Throwable throwable) {
+ this.logger.warn("An error during event handling occured", throwable);
+ }
+
+ private DefaultMessageListenerContainer createQueueListener(String domain) {
+ ActiveMQQueue virtualTopic = new ActiveMQQueue(this.consumerPrefix + "." + this.serviceName + "." + this.virtualTopicPrefix + "." + domain);
+ DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
+ dmlc.setConnectionFactory(this.jmsFactory);
+ dmlc.setErrorHandler(this);
+ dmlc.setConcurrency(this.consumers);
+ dmlc.setDestination(virtualTopic);
+ dmlc.setMessageListener(this);
+ dmlc.afterPropertiesSet();
+ dmlc.start();
+ return dmlc;
+ }
+
+ private Collection getDomains() {
+ Set result = new HashSet<>();
+ if(this.eventHandlers == null || this.eventHandlers.isEmpty()) {
+ return result;
+ }
+ for(IEventHandler eventHandler : this.eventHandlers) {
+ if(eventHandler == null || eventHandler.getEventType() == null) {
+ continue;
+ }
+ Annotation domainAnnotation = AnnotationUtils.findAnnotation(eventHandler.getEventType(), EventDomain.class);
+ if(domainAnnotation != null && !((EventDomain) domainAnnotation).value().isEmpty()) {
+ result.add(((EventDomain) domainAnnotation).value());
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/AccessException.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/AccessException.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/AccessException.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/AccessException.java
index 6dd8ed7f..26d55a84 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/AccessException.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/AccessException.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/InfrastructureException.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/InfrastructureException.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/InfrastructureException.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/InfrastructureException.java
index 446978f0..1662bc8a 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/InfrastructureException.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/InfrastructureException.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/MessageCryptoException.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/MessageCryptoException.java
new file mode 100644
index 00000000..824f0529
--- /dev/null
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/MessageCryptoException.java
@@ -0,0 +1,62 @@
+package de.taimos.dvalin.interconnect.core.exceptions;
+
+/*
+ * #%L
+ * Dvalin interconnect transfer data model
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+/**
+ * An exception for JMS message base crypto errors
+ *
+ * @author fzwirn
+ */
+public class MessageCryptoException extends Exception {
+
+
+ private static final long serialVersionUID = -6378917176126978412L;
+
+ /**
+ * default constructor
+ */
+ public MessageCryptoException() {
+ this("Message security check failed");
+ }
+
+ /**
+ * @param cause of the exception
+ */
+ public MessageCryptoException(Throwable cause) {
+ this("Message security check failed", cause);
+ }
+
+ /**
+ * @param message the exception message
+ */
+ public MessageCryptoException(String message) {
+ super(message);
+ }
+
+ /**
+ * @param message the exception message
+ * @param cause the root cause
+ */
+ public MessageCryptoException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/SerializationException.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/SerializationException.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/SerializationException.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/SerializationException.java
index 575b3d2b..5ad907ee 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/SerializationException.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/SerializationException.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/TimeoutException.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/TimeoutException.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/TimeoutException.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/TimeoutException.java
index 41fc8186..2d508389 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/TimeoutException.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/TimeoutException.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/VersionMismatchException.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/VersionMismatchException.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/VersionMismatchException.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/VersionMismatchException.java
index a0eb406d..fb2fe765 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/VersionMismatchException.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/exceptions/VersionMismatchException.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageListener.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageListener.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageListener.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageListener.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSender.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSender.java
similarity index 98%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSender.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSender.java
index bb568387..bde30395 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSender.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSender.java
@@ -25,7 +25,7 @@
import de.taimos.dvalin.interconnect.core.MessageConnector;
import de.taimos.dvalin.interconnect.core.daemon.DaemonResponse;
import de.taimos.dvalin.interconnect.core.exceptions.InfrastructureException;
-import de.taimos.dvalin.interconnect.model.CryptoException;
+import de.taimos.dvalin.interconnect.core.exceptions.MessageCryptoException;
import de.taimos.dvalin.interconnect.model.InterconnectMapper;
import de.taimos.dvalin.interconnect.model.InterconnectObject;
import org.slf4j.Logger;
@@ -116,7 +116,7 @@ private MessageCreator createMessageCreator(String correlationID, InterconnectOb
if (secure) {
try {
MessageConnector.secureMessage(textMessage);
- } catch (CryptoException e) {
+ } catch (MessageCryptoException e) {
throw new JMSException(e.getMessage());
}
}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSenderHeader.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSenderHeader.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSenderHeader.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonMessageSenderHeader.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonProxyFactory.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonProxyFactory.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonProxyFactory.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonProxyFactory.java
index 1fdc7f7b..fe6b1a2f 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonProxyFactory.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/DaemonProxyFactory.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageHandlerFactory.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageHandlerFactory.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageHandlerFactory.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageHandlerFactory.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageSender.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageSender.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageSender.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageSender.java
index 0f3115aa..cd9c0579 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageSender.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/IDaemonMessageSender.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/InterconnectBeanPostProcessor.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/InterconnectBeanPostProcessor.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/InterconnectBeanPostProcessor.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/InterconnectBeanPostProcessor.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/MultiDaemonMessageHandler.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/MultiDaemonMessageHandler.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/MultiDaemonMessageHandler.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/MultiDaemonMessageHandler.java
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/RequestHandler.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/RequestHandler.java
similarity index 99%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/RequestHandler.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/RequestHandler.java
index f8d0b198..0b29d021 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/RequestHandler.java
+++ b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/RequestHandler.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/SingleDaemonMessageHandler.java b/interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/SingleDaemonMessageHandler.java
similarity index 100%
rename from interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/spring/SingleDaemonMessageHandler.java
rename to interconnect/core-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/SingleDaemonMessageHandler.java
diff --git a/interconnect/test/src/main/resources/.gitkeep b/interconnect/core-legacy/src/main/resources/.gitkeep
similarity index 100%
rename from interconnect/test/src/main/resources/.gitkeep
rename to interconnect/core-legacy/src/main/resources/.gitkeep
diff --git a/interconnect/test/src/test/java/.gitkeep b/interconnect/core-legacy/src/test/java/.gitkeep
similarity index 100%
rename from interconnect/test/src/test/java/.gitkeep
rename to interconnect/core-legacy/src/test/java/.gitkeep
diff --git a/interconnect/test/src/test/resources/.gitkeep b/interconnect/core-legacy/src/test/resources/.gitkeep
similarity index 100%
rename from interconnect/test/src/test/resources/.gitkeep
rename to interconnect/core-legacy/src/test/resources/.gitkeep
diff --git a/interconnect/core/dvalin-interconnect-core.iml b/interconnect/core/dvalin-interconnect-core.iml
index cf92348d..a3dcbad8 100644
--- a/interconnect/core/dvalin-interconnect-core.iml
+++ b/interconnect/core/dvalin-interconnect-core.iml
@@ -1,11 +1,19 @@
+
+
+
+
+
-
-
- file://$MODULE_DIR$/src/main/java/de/taimos/dvalin/interconnect/core/config/JMSConfig.java
+
+ file://$MODULE_DIR$/src/main/java/de/taimos/dvalin/interconnect/core/config/InterconnectConfig.java
+ file://$MODULE_DIR$/../../daemon/src/main/resources/spring/dvalin.xml
+ file://$MODULE_DIR$/../../daemon/src/main/resources/spring/daemon.xml
+ file://$MODULE_DIR$/src/main/java/de/taimos/dvalin/interconnect/core/config/MultiRequestHandlerConfig.java
+ file://$MODULE_DIR$/../../jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/config/JMSConfig.java
diff --git a/interconnect/core/pom.xml b/interconnect/core/pom.xml
index d559ccd6..871e19c1 100644
--- a/interconnect/core/pom.xml
+++ b/interconnect/core/pom.xml
@@ -20,16 +20,11 @@
dvalin-interconnect-model
${project.version}
-
-
- org.apache.activemq
- activemq-pool
- ${activemq.version}
-
- org.apache.activemq
- activemq-client
- ${activemq.version}
+ de.taimos
+ dvalin-jms-core
+ ${project.version}
+ compile
@@ -106,5 +101,6 @@
${org.springframework.version}
test
+
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/AToTopicSender.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/AToTopicSender.java
new file mode 100644
index 00000000..fcd255a2
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/AToTopicSender.java
@@ -0,0 +1,70 @@
+package de.taimos.dvalin.interconnect.core;
+
+/*-
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 - 2017 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.interconnect.core.daemon.util.DaemonExceptionMapper;
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.jms.IJmsConnector;
+import de.taimos.dvalin.jms.exceptions.InfrastructureException;
+import de.taimos.dvalin.jms.exceptions.SerializationException;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
+import de.taimos.dvalin.jms.model.JmsContext.JmsContextBuilder;
+import de.taimos.dvalin.jms.model.JmsTarget;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+
+/**
+ * This class handles sending messages.
+ *
+ * @author fzwirn
+ */
+public abstract class AToTopicSender implements IToTopicSender {
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+
+ protected IJmsConnector jmsConnector;
+
+ protected AToTopicSender(IJmsConnector jmsConnector) {
+ this.jmsConnector = jmsConnector;
+ }
+
+ /**
+ * @param object the object
+ * @param topicName name of the topic you want to use
+ * @throws DaemonError is throw if there is a problem with sending the event
+ */
+ public void send(Serializable object, String topicName) throws DaemonError, TimeoutException {
+ if (topicName == null) {
+ this.logger.error("Invalid topic name: a non-null name is required");
+ throw new IllegalArgumentException("Invalid topic name: a non-null name is required");
+ }
+ JmsContextBuilder context = new JmsContextBuilder().withTarget(JmsTarget.TOPIC)
+ .withDestinationName(topicName).withBody(object);
+
+ try {
+ this.jmsConnector.send(context.build());
+ } catch (InfrastructureException | SerializationException e) {
+ DaemonExceptionMapper.mapAndThrow(e);
+ }
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/EventSender.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/EventSender.java
index 9437f675..f0c61592 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/EventSender.java
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/EventSender.java
@@ -20,42 +20,41 @@
* #L%
*/
-import de.taimos.dvalin.interconnect.model.InterconnectMapper;
import de.taimos.dvalin.interconnect.model.event.EventDomain;
import de.taimos.dvalin.interconnect.model.event.IEvent;
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.jms.IJmsConnector;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
import org.springframework.core.annotation.AnnotationUtils;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.Session;
-import java.io.IOException;
import java.io.Serializable;
-import java.lang.annotation.Annotation;
-public class EventSender extends ToTopicSender {
+/**
+ * Event sender
+ *
+ * @author psigloch, fzwirn
+ */
+@SuppressWarnings("unused")
+public class EventSender extends AToTopicSender {
private static final String PROP_DEFAULT_VIRTUAL_TOPIC_PREFIX = "VirtualTopic";
- private static EventSender instance = new EventSender();
- private String virtualTopicPrefix;
-
- private EventSender() {
- super();
- this.virtualTopicPrefix = System.getProperty(MessageConnector.SYSPROP_VIRTUAL_TOPIC_PREFIX, EventSender.PROP_DEFAULT_VIRTUAL_TOPIC_PREFIX);
- }
+ private final String virtualTopicPrefix;
/**
- * @return the singleton
+ * @param jmsConnector that will create the JMS connections
*/
- public static EventSender getInstance() {
- return EventSender.instance;
+ public EventSender(IJmsConnector jmsConnector) {
+ super(jmsConnector);
+ this.virtualTopicPrefix = System.getProperty(IJmsConnector.SYSPROP_VIRTUAL_TOPIC_PREFIX,
+ EventSender.PROP_DEFAULT_VIRTUAL_TOPIC_PREFIX);
}
@Override
- public void send(Serializable object, String topicName) {
- if(object instanceof IEvent) {
+ public void send(Serializable object, String topicName) throws DaemonError, TimeoutException {
+ if (object instanceof IEvent) {
this.send((IEvent) object);
} else {
super.send(object, topicName);
@@ -64,25 +63,19 @@ public void send(Serializable object, String topicName) {
/**
* @param object the object
+ * @throws DaemonError with specific error code
+ * @throws TimeoutException in case of communication timeout
*/
- public void send(IEvent object) {
- Annotation domainAnnotation = AnnotationUtils.findAnnotation(object.getClass(), EventDomain.class);
- if(domainAnnotation == null) {
+ public void send(IEvent object) throws DaemonError, TimeoutException {
+ EventDomain domainAnnotation = AnnotationUtils.findAnnotation(object.getClass(), EventDomain.class);
+ if (domainAnnotation == null) {
this.logger.error("The event {} has no domain annotation", object.getClass().getSimpleName());
return;
}
- if(((EventDomain) domainAnnotation).value().isEmpty()) {
+ if (domainAnnotation.value().isEmpty()) {
this.logger.error("The domainname for the event {} is empty", object.getClass().getSimpleName());
return;
}
- super.send(object, this.virtualTopicPrefix + "." + ((EventDomain) domainAnnotation).value());
- }
-
- protected Message getMessage(Serializable object, Session session) throws JMSException, IOException {
- if(object instanceof IEvent) {
- String json = InterconnectMapper.toJson((IEvent) object);
- return session.createTextMessage(json);
- }
- return session.createObjectMessage(object);
+ super.send(object, this.virtualTopicPrefix + "." + domainAnnotation.value());
}
}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/IToTopicSender.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/IToTopicSender.java
new file mode 100644
index 00000000..6fa1373e
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/IToTopicSender.java
@@ -0,0 +1,23 @@
+package de.taimos.dvalin.interconnect.core;
+
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
+
+import java.io.Serializable;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public interface IToTopicSender {
+ /**
+ * @param object the object
+ * @param topicName name of the topic you want to use
+ * @throws DaemonError with specific error code
+ * @throws TimeoutException in case of communication timeout
+ */
+ void send(Serializable object, String topicName) throws DaemonError, TimeoutException;
+
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/IVORefreshSender.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/IVORefreshSender.java
index a427d3b0..330ac1e5 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/IVORefreshSender.java
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/IVORefreshSender.java
@@ -23,27 +23,34 @@
* #L%
*/
-import java.io.Serializable;
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.jms.IJmsConnector;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
-public class IVORefreshSender extends ToTopicSender {
+import java.io.Serializable;
- private static IVORefreshSender instance = new IVORefreshSender();
+/**
+ * Abstract IVO refresh sender.
+ *
+ * @author psigloch, fzwirn
+ */
+@SuppressWarnings("unused")
+public class IVORefreshSender extends AToTopicSender {
- private IVORefreshSender() {
- super();
- }
/**
- * @return the singleton
+ * @param jmsConnector that will create the JMS connections
*/
- public static IVORefreshSender getInstance() {
- return IVORefreshSender.instance;
+ public IVORefreshSender(IJmsConnector jmsConnector) {
+ super(jmsConnector);
}
/**
* @param object the object
+ * @throws DaemonError with specific error code
+ * @throws TimeoutException in case of communication timeout
*/
- public void send(Serializable object) {
- this.send(object, System.getProperty(MessageConnector.SYSPROP_UPDATE_TOPIC));
+ public void send(Serializable object) throws DaemonError, TimeoutException {
+ this.send(object, System.getProperty(IJmsConnector.SYSPROP_UPDATE_TOPIC));
}
}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/config/InterconnectConfig.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/config/InterconnectConfig.java
new file mode 100644
index 00000000..90503317
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/config/InterconnectConfig.java
@@ -0,0 +1,96 @@
+package de.taimos.dvalin.interconnect.core.config;
+
+import de.taimos.dvalin.interconnect.core.EventSender;
+import de.taimos.dvalin.interconnect.core.IVORefreshSender;
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageHandlerFactory;
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageSender;
+import de.taimos.dvalin.interconnect.core.daemon.handler.DefaultMessageHandlerFactory;
+import de.taimos.dvalin.interconnect.core.daemon.jms.DaemonMessageListener;
+import de.taimos.dvalin.jms.DvalinConnectionFactory;
+import de.taimos.dvalin.jms.IDestinationService;
+import de.taimos.dvalin.jms.IJmsConnector;
+import de.taimos.dvalin.jms.crypto.ICryptoService;
+import de.taimos.dvalin.jms.model.JmsTarget;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.jms.listener.DefaultMessageListenerContainer;
+
+import javax.jms.Destination;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+@Configuration
+@Profile(de.taimos.daemon.spring.Configuration.PROFILES_PRODUCTION)
+public class InterconnectConfig {
+
+ @Value("${interconnect.jms.consumers:2-8}")
+ private String consumers;
+
+ @Value("${serviceName}")
+ private String serviceName;
+
+ /**
+ * @param applicationContext spring application context
+ * @param cryptoService used for encryption and decryption
+ * @param messageSender for sending messages
+ * @param requestHandlerMode mode of the request handler: "multi" has special handling
+ * @return a daemon message handler factory
+ */
+ @Bean
+ public IDaemonMessageHandlerFactory createDaemonMessageHandlerFactory(ApplicationContext applicationContext, //
+ ICryptoService cryptoService, //
+ IDaemonMessageSender messageSender, //
+ @Value("${interconnect.requesthandler.mode:}") String requestHandlerMode) {
+ return new DefaultMessageHandlerFactory(applicationContext, messageSender, cryptoService, requestHandlerMode);
+ }
+
+ /**
+ * @param jmsFactory JMS factory
+ * @param defaultDaemonRequestDestination destination used for the daemon message listener
+ * @param handlerFactory message handler factory
+ * @return default message listener container
+ */
+ @Bean(name = "messageListener", destroyMethod = "stop")
+ public DefaultMessageListenerContainer jmsListenerContainer(@Qualifier("DvalinConnectionFactory") DvalinConnectionFactory jmsFactory, //
+ @Qualifier("defaultDaemonRequestDestination") Destination defaultDaemonRequestDestination, //
+ IDaemonMessageHandlerFactory handlerFactory) {
+ return new DaemonMessageListener(jmsFactory, this.consumers, handlerFactory::create,
+ defaultDaemonRequestDestination);
+ }
+
+ /**
+ * @param destinationService creates the default daemon request destination
+ * @return default daemon request destination
+ */
+ @Bean(name = "defaultDaemonRequestDestination")
+ public Destination getDefaultDaemonRequestDestination(IDestinationService destinationService) {
+ return destinationService.createDestination(JmsTarget.QUEUE,
+ this.serviceName + ".request");
+ }
+
+ /**
+ * @param jmsConnector JMS connector to be used
+ * @return an instance of a new event sender
+ */
+ @Bean
+ public EventSender eventSender(IJmsConnector jmsConnector) {
+ return new EventSender(jmsConnector);
+ }
+
+ /**
+ * @param jmsConnector JMS connector to be used
+ * @return an instance of a new ivo refresh sender
+ */
+ @Bean
+ public IVORefreshSender ivoRefreshSender(IJmsConnector jmsConnector) {
+ return new IVORefreshSender(jmsConnector);
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonMessageHandler.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonMessageHandler.java
new file mode 100644
index 00000000..3ad0313d
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonMessageHandler.java
@@ -0,0 +1,20 @@
+package de.taimos.dvalin.interconnect.core.daemon;
+
+import javax.jms.Message;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public interface IDaemonMessageHandler {
+
+ /**
+ * @param message Message
+ * @throws Exception If no registered method was found for the incomming InterconnectObject or Insecure call or no (valid) Request UUID
+ * or no
+ */
+
+ void onMessage(Message message) throws Exception;
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonMessageHandlerFactory.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonMessageHandlerFactory.java
new file mode 100644
index 00000000..57799e3e
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonMessageHandlerFactory.java
@@ -0,0 +1,19 @@
+package de.taimos.dvalin.interconnect.core.daemon;
+
+import org.slf4j.Logger;
+
+/**
+ * Copyright 2022 Taimos GmbH
+ *
+ *
+ * @author psigloch
+ */
+public interface IDaemonMessageHandlerFactory {
+
+ /**
+ * @param logger the logger to use within the message handler
+ * @return the message handler
+ */
+ IDaemonMessageHandler create(Logger logger);
+
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonMessageSender.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonMessageSender.java
new file mode 100644
index 00000000..2064ac6a
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonMessageSender.java
@@ -0,0 +1,40 @@
+package de.taimos.dvalin.interconnect.core.daemon;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.interconnect.core.daemon.model.InterconnectContext;
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
+
+import java.util.concurrent.Future;
+
+
+/**
+ * Send a response.
+ */
+public interface IDaemonMessageSender {
+
+ void sendRequest(InterconnectContext interconnectContext) throws DaemonError, TimeoutException;
+
+ R syncRequest(InterconnectContext interconnectContext, Class responseClazz) throws DaemonError, TimeoutException;
+
+ Future asyncRequest(InterconnectContext interconnectContext, Class responseClazz);
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonProxyFactory.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonProxyFactory.java
index 9ef44f19..6c4ef75e 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonProxyFactory.java
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/IDaemonProxyFactory.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/RequestHandler.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/RequestHandler.java
new file mode 100644
index 00000000..f966ae5b
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/RequestHandler.java
@@ -0,0 +1,47 @@
+package de.taimos.dvalin.interconnect.core.daemon;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author thoeger
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Component
+@Scope("prototype")
+public @interface RequestHandler {
+
+ /**
+ * The value may indicate a suggestion for a logical component name, to be turned into a Spring bean in case of an autodetected
+ * component.
+ *
+ * @return the suggested component name, if any
+ */
+ String value() default "requestHandler";
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/exceptions/FrameworkErrors.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/exceptions/FrameworkErrors.java
new file mode 100644
index 00000000..9d8eb17e
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/exceptions/FrameworkErrors.java
@@ -0,0 +1,61 @@
+package de.taimos.dvalin.interconnect.core.daemon.exceptions;
+
+import de.taimos.dvalin.interconnect.model.service.ADaemonErrorNumber;
+import de.taimos.dvalin.interconnect.model.service.DaemonErrorNumber;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class FrameworkErrors {
+ public static final DaemonErrorNumber FRAMEWORK_ERROR = new FrameworkError(-1);
+
+ public static final DaemonErrorNumber UNEXPECTED_TYPE_ERROR = new FrameworkError(-20);
+
+ public static final DaemonErrorNumber SEND_ERROR = new FrameworkError(-50);
+ public static final DaemonErrorNumber RETRY_FAILED_ERROR = new FrameworkError(-51);
+ public static final DaemonErrorNumber RECEIVE_ERROR = new FrameworkError(-52);
+ public static final DaemonErrorNumber INVALID_RESPONSE_ERROR = new FrameworkError(-53);
+
+ public static final DaemonErrorNumber CONNECT_CREATION_ERROR = new FrameworkError(-70);
+ public static final DaemonErrorNumber SESSION_CREATION_ERROR = new FrameworkError(-71);
+ public static final DaemonErrorNumber CONSUMER_CREATION_ERROR = new FrameworkError(-72);
+ public static final DaemonErrorNumber PRODUCER_CREATION_ERROR = new FrameworkError(-73);
+ public static final DaemonErrorNumber REPLY_TO_DESTINATION_CREATION_ERROR = new FrameworkError(-74);
+ public static final DaemonErrorNumber DESTINATION_CREATION_ERROR = new FrameworkError(-75);
+ public static final DaemonErrorNumber MESSAGE_CREATION_ERROR = new FrameworkError(-76);
+
+ public static final DaemonErrorNumber MESSAGE_SERIALIZATION = new FrameworkError(-90);
+ public static final DaemonErrorNumber MESSAGE_CRYPTO_ERROR = new FrameworkError(-91);
+
+
+ private FrameworkErrors() {
+ super();
+ }
+
+
+ private static final class FrameworkError extends ADaemonErrorNumber {
+ private static final long serialVersionUID = -8496144395438169164L;
+
+ FrameworkError(int aNumber) {
+ super(aNumber, "framework");
+ }
+ }
+
+ public static final class GenericError extends ADaemonErrorNumber {
+
+ private static final long serialVersionUID = 7705178009518714330L;
+
+ /**
+ * @param aNumber error number
+ * @param aDaemon daemon
+ */
+ public GenericError(int aNumber, String aDaemon) {
+ super(aNumber, aDaemon);
+ }
+
+ }
+
+}
diff --git a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/CryptoException.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/exceptions/IdemponentRetryException.java
similarity index 57%
rename from interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/CryptoException.java
rename to interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/exceptions/IdemponentRetryException.java
index 04388fef..6997c1ba 100644
--- a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/CryptoException.java
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/exceptions/IdemponentRetryException.java
@@ -1,17 +1,17 @@
-package de.taimos.dvalin.interconnect.model;
+package de.taimos.dvalin.interconnect.core.daemon.exceptions;
/*
* #%L
- * Dvalin interconnect transfer data model
+ * Dvalin interconnect core library
* %%
* Copyright (C) 2016 Taimos GmbH
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,24 +20,22 @@
* #L%
*/
-public class CryptoException extends Exception {
-
- private static final long serialVersionUID = 1L;
+/**
+ * Forces a idempotent method call to be retried because of an exception.
+ */
+public final class IdemponentRetryException extends RuntimeException {
+ /**
+ * Serial version uid.
+ */
+ private static final long serialVersionUID = 480732299475266442L;
- /**
- * @param message the exception message
- */
- public CryptoException(String message) {
- super(message);
- }
/**
- * @param message the exception message
- * @param cause the root cause
+ * @param cause Cause
*/
- public CryptoException(String message, Throwable cause) {
- super(message, cause);
+ public IdemponentRetryException(Throwable cause) {
+ super(cause);
}
}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/exceptions/UnexpectedTypeException.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/exceptions/UnexpectedTypeException.java
new file mode 100644
index 00000000..ca95218e
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/exceptions/UnexpectedTypeException.java
@@ -0,0 +1,18 @@
+package de.taimos.dvalin.interconnect.core.daemon.exceptions;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class UnexpectedTypeException extends Exception {
+ private static final long serialVersionUID = -4471574748172345123L;
+
+ /**
+ * @param s messaage of the exception
+ */
+ public UnexpectedTypeException(String s) {
+ super(s);
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/ADaemonMessageHandler.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/ADaemonMessageHandler.java
new file mode 100644
index 00000000..ff06024c
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/ADaemonMessageHandler.java
@@ -0,0 +1,348 @@
+package de.taimos.dvalin.interconnect.core.daemon.handler;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageHandler;
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageSender;
+import de.taimos.dvalin.interconnect.core.daemon.exceptions.FrameworkErrors;
+import de.taimos.dvalin.interconnect.core.daemon.exceptions.IdemponentRetryException;
+import de.taimos.dvalin.interconnect.core.daemon.model.HandlingDuration;
+import de.taimos.dvalin.interconnect.core.daemon.model.HandlingDurationType;
+import de.taimos.dvalin.interconnect.core.daemon.model.InterconnectContext;
+import de.taimos.dvalin.interconnect.core.daemon.model.InterconnectResponseContext;
+import de.taimos.dvalin.interconnect.core.daemon.util.DaemonMethodRegistry;
+import de.taimos.dvalin.interconnect.core.daemon.util.DaemonMethodRegistry.RegistryEntry;
+import de.taimos.dvalin.interconnect.model.InterconnectObject;
+import de.taimos.dvalin.interconnect.model.ivo.IPageable;
+import de.taimos.dvalin.interconnect.model.ivo.IVO;
+import de.taimos.dvalin.interconnect.model.ivo.daemon.DaemonErrorIVO;
+import de.taimos.dvalin.interconnect.model.ivo.daemon.PingIVO;
+import de.taimos.dvalin.interconnect.model.ivo.daemon.PongIVO;
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.interconnect.model.service.DaemonScanner;
+import de.taimos.dvalin.interconnect.model.service.DaemonScanner.DaemonMethod;
+import de.taimos.dvalin.interconnect.model.service.IDaemonHandler;
+import de.taimos.dvalin.jms.crypto.ICryptoService;
+import de.taimos.dvalin.jms.exceptions.MessageCryptoException;
+import org.slf4j.Logger;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.TextMessage;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.UUID;
+
+
+/**
+ * Copyright 2015 Taimos GmbH
+ *
+ *
+ * @author Thorsten Hoeger
+ */
+public abstract class ADaemonMessageHandler implements IDaemonMessageHandler {
+
+ protected final DaemonMethodRegistry registry;
+ protected final ICryptoService cryptoService;
+ protected final IDaemonMessageSender messageSender;
+
+ private final boolean throwExceptionOnTimeout;
+
+
+ protected ADaemonMessageHandler(final Collection> aHandlerClazzes, IDaemonMessageSender messageSender, ICryptoService cryptoService, final boolean aThrowExceptionOnTimeout) {
+ this.registry = new DaemonMethodRegistry(aHandlerClazzes);
+ this.throwExceptionOnTimeout = aThrowExceptionOnTimeout;
+ this.cryptoService = cryptoService;
+ this.messageSender = messageSender;
+ }
+
+
+ /**
+ * Create a new request handler.
+ *
+ * @param registryEntry the registry entry
+ * @return ADaemonHandler
+ */
+ protected abstract IDaemonHandler createRequestHandler(RegistryEntry registryEntry);
+
+ /**
+ * @return the logger
+ */
+ protected abstract Logger getLogger();
+
+ /**
+ * Reply with a Daemon responseContext.
+ *
+ * @param response Response
+ * @throws Exception If something went wrong
+ */
+ protected void reply(final InterconnectResponseContext response) throws Exception {
+ this.messageSender.sendRequest(response.createResponseContext());
+ }
+
+ /**
+ * @param message Message
+ * @throws Exception If no registered method was found for the incomming InterconnectObject or Insecure call or no (valid) Request UUID
+ * or no
+ */
+ @Override
+ public final void onMessage(final Message message) throws Exception {
+ de.taimos.dvalin.interconnect.model.InterconnectContext.reset();
+
+ final long begin = System.currentTimeMillis();
+
+ if (!(message instanceof TextMessage)) {
+ throw new Exception("Invalid message type received: " + message.getClass().getSimpleName());
+ }
+
+ boolean secure = this.cryptoService.isMessageSecure(message);
+ TextMessage receivedTextMessage = (TextMessage) this.decryptIfNecessary(this.cryptoService, message, secure);
+ InterconnectResponseContext context = new InterconnectResponseContext(receivedTextMessage, secure, begin);
+
+ if (context.getReceivedContext().getIcoClass().equals(PingIVO.class)) {
+ this.handlePing(context);
+ return;
+ }
+
+ this.updateThreadContext(context);
+
+ final RegistryEntry registryEntry = this.getRegistryEntry(context);
+
+ final IDaemonHandler handler = this.createRequestHandler(registryEntry);
+
+ final DaemonMethod method = ADaemonMessageHandler.getDaemonMethod(registryEntry, context);
+ context.setCreateResponseMethod(method);
+
+ this.logInvoke(context);
+
+ if (method.getType() == DaemonScanner.Type.voit) {
+ this.handleWithoutReply(handler, context);
+ } else {
+ this.handleWithReply(handler, context);
+ }
+ }
+
+ private Message decryptIfNecessary(ICryptoService cryptoService, Message message, boolean secure) throws MessageCryptoException {
+ if (secure) {
+ return cryptoService.decryptMessage(message);
+ }
+ return message;
+ }
+
+ private void handleWithReply(IDaemonHandler handler, InterconnectResponseContext context) throws Exception {
+ try {
+ final InterconnectObject responseIco = this.handleRequest(handler, context.getCreateResponseMethod(),
+ context.getReceivedContext().getRequestIco());
+ context.setResponseICO(responseIco);
+ if (this.duration(context) == HandlingDurationType.TIMEOUT) {
+ return;
+ }
+ this.reply(context);
+ } catch (final DaemonError e) {
+ this.getLogger().debug("DaemonError for " + context.getCreateResponseMethod().getMethod().getName() + "(" +
+ context.getReceivedContext().getIcoClass().getSimpleName() + ")" + " with " +
+ de.taimos.dvalin.interconnect.model.InterconnectContext.getContext(), e);
+ this.sendErrorResponse(e, context);
+ }
+ }
+
+ private void sendErrorResponse(DaemonError e, InterconnectResponseContext context) throws Exception {
+ final DaemonErrorIVO.DaemonErrorIVOBuilder error = new DaemonErrorIVO.DaemonErrorIVOBuilder();
+ error.number(e.getNumber().get());
+ error.daemon(e.getNumber().daemon());
+ error.message(e.getMessage());
+
+ context.setResponseICO(error.build());
+ this.reply(context);
+ }
+
+ private void updateThreadContext(InterconnectResponseContext context) throws Exception {
+ de.taimos.dvalin.interconnect.model.InterconnectContext.setUuid(
+ ADaemonMessageHandler.getUuid(context.getReceivedMessage(),
+ context.getReceivedContext().getIcoClass()));
+ de.taimos.dvalin.interconnect.model.InterconnectContext.setDeliveryCount(
+ this.getDeliveryCount(context.getReceivedMessage()));
+ de.taimos.dvalin.interconnect.model.InterconnectContext.setRedelivered(
+ context.getReceivedMessage().getJMSRedelivered());
+ Class extends IVO> ivoClass;
+ if (context.getReceivedContext() instanceof IVO) {
+ ivoClass = ADaemonMessageHandler.uncheckedCast(context.getResponseICO());
+ de.taimos.dvalin.interconnect.model.InterconnectContext.setRequestClass(ivoClass);
+ }
+ }
+
+ private static DaemonMethod getDaemonMethod(RegistryEntry registryEntry, InterconnectResponseContext context) throws Exception {
+ final DaemonMethod method = registryEntry.getMethod();
+ if (method.isSecure() != context.getReceivedContext().isSecure()) {
+ throw new Exception(
+ "Insecure call (is " + context.getReceivedContext().isSecure() + " should be " + method.isSecure() +
+ ") for " + context.getReceivedContext().getIcoClass().getSimpleName() + " from " +
+ context.getReceivedMessage().getJMSReplyTo());
+ }
+ return method;
+ }
+
+ private RegistryEntry getRegistryEntry(InterconnectResponseContext context) throws Exception {
+ final RegistryEntry registryEntry = this.registry.get(context.getReceivedContext().getIcoClass());
+ if (registryEntry == null) {
+ throw new Exception(
+ "No registered method found for " + context.getReceivedContext().getIcoClass().getSimpleName() +
+ " from " + context.getReceivedMessage().getJMSReplyTo());
+ }
+ return registryEntry;
+ }
+
+ private void handlePing(InterconnectResponseContext context) throws Exception {
+ context.setResponseICO(new PongIVO.PongIVOBuilder().build());
+ this.reply(context);
+ }
+
+ private HandlingDurationType duration(InterconnectResponseContext context) throws Exception {
+ HandlingDuration handlingDuration = context.handlingDuration();
+ switch (handlingDuration.getHandlingDurationType()) {
+ case TIMEOUT:
+ if (this.throwExceptionOnTimeout) {
+ throw new Exception(context.timeoutMessage());
+ }
+ this.getLogger().warn(context.timeoutMessage());
+ break;
+ case SLOW_RESPONSE:
+ this.getLogger().info(context.slowResponseMessage());
+ break;
+ default:
+ break;
+ }
+ return handlingDuration.getHandlingDurationType();
+ }
+
+ private void logInvoke(InterconnectResponseContext context) {
+ if (this.getLogger().isInfoEnabled()) {
+ final StringBuilder sbInvokeLog = new StringBuilder() //
+ .append("Invoke ") //
+ .append(context.getCreateResponseMethod().getMethod().getName()) //
+ .append("(").append(context.getReceivedContext().getIcoClass().getSimpleName()).append(")");
+ if (context.getReceivedContext().getRequestIco() instanceof IPageable) {
+ sbInvokeLog //
+ .append(" at Page ").append(((IPageable) context.getReceivedContext().getRequestIco()).getOffset())
+ .append(";").append(((IPageable) context.getReceivedContext().getRequestIco()).getLimit());
+ }
+ sbInvokeLog.append(" with ").append(de.taimos.dvalin.interconnect.model.InterconnectContext.getContext());
+ this.getLogger().info(sbInvokeLog.toString());
+ }
+ }
+
+ private int getDeliveryCount(Message message) throws JMSException {
+ int deliveryCount;
+ try {
+ deliveryCount = message.getIntProperty("JMSXDeliveryCount");
+ } catch (final Exception e) {
+ if (message.getJMSRedelivered()) {
+ deliveryCount = 2;
+ } else {
+ deliveryCount = 1;
+ }
+ this.getLogger().warn("Can not get JMSXDeliveryCount");
+ }
+ return deliveryCount;
+ }
+
+ private static UUID getUuid(Message message, Class extends InterconnectObject> icoClass) throws Exception {
+ final String requestUUID = message.getStringProperty(InterconnectContext.HEADER_REQUEST_UUID);
+ if (requestUUID == null) {
+ throw new Exception("No request UUID found in message with " + icoClass.getSimpleName() + " from " +
+ message.getJMSReplyTo());
+ }
+ try {
+ return UUID.fromString(requestUUID);
+ } catch (final IllegalArgumentException e) {
+ throw new Exception(
+ "No valid request UUID " + requestUUID + " message with " + icoClass.getSimpleName() + " from " +
+ message.getJMSReplyTo());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Class extends IVO> uncheckedCast(InterconnectObject ivoIn) {
+ return (Class extends IVO>) ivoIn.getClass();
+ }
+
+ private static Throwable extractTargetException(final InvocationTargetException e) {
+ if (e.getTargetException() != null) {
+ return e.getTargetException();
+ }
+ return e;
+ }
+
+ /**
+ * @param handler Handler
+ * @param method Method
+ * @param ico Request
+ * @return Response
+ * @throws DaemonError Forward...
+ */
+ private InterconnectObject handleRequest(final IDaemonHandler handler, final DaemonScanner.DaemonMethod method, final InterconnectObject ico) throws DaemonError {
+ handler.beforeRequestHook();
+ try {
+ return method.invoke(handler, ico);
+ } catch (final InvocationTargetException e) {
+ if (e.getTargetException() instanceof DaemonError) {
+ throw (DaemonError) e.getTargetException();
+ }
+ if (e.getTargetException() instanceof RuntimeException) {
+ handler.exceptionHook((RuntimeException) e.getTargetException());
+ }
+ final Throwable targetException = ADaemonMessageHandler.extractTargetException(e);
+ if (method.isIdempotent()) {
+ throw new IdemponentRetryException(targetException);
+ }
+
+ this.getLogger().error(
+ "Exception in non-idempotent " + method.getMethod().getName() + "(" + ico.getClass().getSimpleName() +
+ ")" + " with " + de.taimos.dvalin.interconnect.model.InterconnectContext.getContext(), e);
+ throw new DaemonError(FrameworkErrors.FRAMEWORK_ERROR, targetException);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ handler.afterRequestHook();
+ }
+ }
+
+ /**
+ * @param handler Handler
+ */
+ private void handleWithoutReply(final IDaemonHandler handler, InterconnectResponseContext context) {
+ handler.beforeRequestHook();
+ try {
+ context.getCreateResponseMethod().invoke(handler, context.getReceivedContext().getRequestIco());
+ } catch (final InvocationTargetException e) {
+ final Throwable targetException = ADaemonMessageHandler.extractTargetException(e);
+ if (context.getCreateResponseMethod().isIdempotent()) {
+ throw new IdemponentRetryException(targetException);
+ }
+ throw new RuntimeException(targetException);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ handler.afterRequestHook();
+ }
+ }
+
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/DefaultMessageHandlerFactory.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/DefaultMessageHandlerFactory.java
new file mode 100644
index 00000000..3e834098
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/DefaultMessageHandlerFactory.java
@@ -0,0 +1,65 @@
+package de.taimos.dvalin.interconnect.core.daemon.handler;
+
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageHandler;
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageHandlerFactory;
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageSender;
+import de.taimos.dvalin.interconnect.core.daemon.RequestHandler;
+import de.taimos.dvalin.interconnect.model.service.ADaemonHandler;
+import de.taimos.dvalin.interconnect.model.service.IDaemonHandler;
+import de.taimos.dvalin.jms.crypto.ICryptoService;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.context.ApplicationContext;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class DefaultMessageHandlerFactory implements IDaemonMessageHandlerFactory {
+ private final ApplicationContext applicationContext;
+ private final IDaemonMessageSender messageSender;
+ private final ICryptoService cryptoService;
+ private final String requestHandlerMode;
+
+ /**
+ * @param applicationContext spring application context
+ * @param messageSender to use for the message handler
+ * @param cryptoService for encryption and decryption of messages
+ * @param requestHandlerMode mode of the request handler: "multi" has special handling
+ */
+ public DefaultMessageHandlerFactory(ApplicationContext applicationContext, IDaemonMessageSender messageSender, ICryptoService cryptoService, String requestHandlerMode) {
+ this.applicationContext = applicationContext;
+ this.messageSender = messageSender;
+ this.cryptoService = cryptoService;
+ this.requestHandlerMode = requestHandlerMode;
+ }
+
+ public IDaemonMessageHandler create(Logger logger) {
+ AutowireCapableBeanFactory beanFactory = this.applicationContext.getAutowireCapableBeanFactory();
+ if ("multi".equals(this.requestHandlerMode)) {
+ return this.createMultiDaemonMessageHandler(logger, beanFactory);
+ }
+ return this.createSingleDaemonMessageHandler(logger, beanFactory);
+ }
+
+ private SingleDaemonMessageHandler createSingleDaemonMessageHandler(Logger logger, AutowireCapableBeanFactory beanFactory) {
+ final ADaemonHandler rh = (ADaemonHandler) beanFactory.getBean("requestHandler");
+ return new SingleDaemonMessageHandler(logger, rh.getClass(), this.cryptoService, this.messageSender,
+ beanFactory);
+ }
+
+ private MultiDaemonMessageHandler createMultiDaemonMessageHandler(Logger logger, AutowireCapableBeanFactory beanFactory) {
+ Set> handlers = new HashSet<>();
+ for (Object o : this.applicationContext.getBeansWithAnnotation(RequestHandler.class).values()) {
+ if (o instanceof IDaemonHandler) {
+ handlers.add(((IDaemonHandler) o).getClass());
+ }
+ }
+ return new MultiDaemonMessageHandler(logger, handlers, this.cryptoService, this.messageSender, beanFactory);
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/MultiDaemonMessageHandler.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/MultiDaemonMessageHandler.java
new file mode 100644
index 00000000..f5df5b95
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/MultiDaemonMessageHandler.java
@@ -0,0 +1,48 @@
+package de.taimos.dvalin.interconnect.core.daemon.handler;
+
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageSender;
+import de.taimos.dvalin.interconnect.core.daemon.util.DaemonMethodRegistry.RegistryEntry;
+import de.taimos.dvalin.interconnect.model.service.IDaemonHandler;
+import de.taimos.dvalin.jms.crypto.ICryptoService;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.BeanFactory;
+
+import java.util.Collection;
+
+/**
+ * Copyright 2022 Taimos GmbH
+ *
+ *
+ * @author psigloch
+ */
+public class MultiDaemonMessageHandler extends ADaemonMessageHandler {
+
+ private final Logger logger;
+
+
+ private final BeanFactory beanFactory;
+
+
+ /**
+ * @param aLogger the logger
+ * @param aHandlerClazzes the handler classes
+ * @param cryptoService the message crypt service
+ * @param aMessageSender the message sender
+ * @param beanFactory the bean factory
+ */
+ public MultiDaemonMessageHandler(final Logger aLogger, final Collection> aHandlerClazzes, final ICryptoService cryptoService, final IDaemonMessageSender aMessageSender, BeanFactory beanFactory) {
+ super(aHandlerClazzes, aMessageSender, cryptoService, false);
+ this.logger = aLogger;
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ protected IDaemonHandler createRequestHandler(RegistryEntry registryEntry) {
+ return this.beanFactory.getBean(registryEntry.getHandlerClazz());
+ }
+
+ @Override
+ protected Logger getLogger() {
+ return this.logger;
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/SingleDaemonMessageHandler.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/SingleDaemonMessageHandler.java
new file mode 100644
index 00000000..52c5e0f9
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/handler/SingleDaemonMessageHandler.java
@@ -0,0 +1,48 @@
+package de.taimos.dvalin.interconnect.core.daemon.handler;
+
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageSender;
+import de.taimos.dvalin.interconnect.core.daemon.util.DaemonMethodRegistry.RegistryEntry;
+import de.taimos.dvalin.interconnect.model.service.ADaemonHandler;
+import de.taimos.dvalin.interconnect.model.service.IDaemonHandler;
+import de.taimos.dvalin.jms.crypto.ICryptoService;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.BeanFactory;
+
+import java.util.Collections;
+
+/**
+ * Copyright 2022 Taimos GmbH
+ *
+ *
+ * @author psigloch
+ */
+public class SingleDaemonMessageHandler extends ADaemonMessageHandler {
+
+ private final Logger logger;
+
+ private final BeanFactory beanFactory;
+
+
+ /**
+ * @param aLogger the logger
+ * @param aHandlerClazz the handler clazz
+ * @param cryptoService the message acrype service
+ * @param aMessageSender the message sender
+ * @param beanFactory the bean factory
+ */
+ public SingleDaemonMessageHandler(final Logger aLogger, final Class extends ADaemonHandler> aHandlerClazz, final ICryptoService cryptoService, final IDaemonMessageSender aMessageSender, BeanFactory beanFactory) {
+ super(Collections.singleton(aHandlerClazz), aMessageSender, cryptoService, false);
+ this.logger = aLogger;
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ protected IDaemonHandler createRequestHandler(RegistryEntry registryEntry) {
+ return (ADaemonHandler) this.beanFactory.getBean("requestHandler");
+ }
+
+ @Override
+ protected Logger getLogger() {
+ return this.logger;
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/jms/DaemonMessageListener.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/jms/DaemonMessageListener.java
new file mode 100644
index 00000000..3fc49b3d
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/jms/DaemonMessageListener.java
@@ -0,0 +1,87 @@
+package de.taimos.dvalin.interconnect.core.daemon.jms;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageHandler;
+import de.taimos.dvalin.interconnect.core.daemon.exceptions.IdemponentRetryException;
+import de.taimos.dvalin.jms.DvalinConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jms.listener.DefaultMessageListenerContainer;
+import org.springframework.lang.NonNull;
+import org.springframework.util.ErrorHandler;
+
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import java.util.function.Function;
+
+
+/**
+ * Listen to JMS messages for this daemon.
+ *
+ * @author thoeger/psigloch
+ */
+public final class DaemonMessageListener extends DefaultMessageListenerContainer
+ implements MessageListener, ErrorHandler {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final IDaemonMessageHandler handler;
+
+ /**
+ * @param jmsFactory JMS factory
+ * @param concurrentConsumers to use for this message listener
+ * @param handlerCreator create for {@link IDaemonMessageHandler}
+ * @param destination for the message listener
+ */
+ public DaemonMessageListener(DvalinConnectionFactory jmsFactory, String concurrentConsumers, Function handlerCreator, Destination destination) {
+ super();
+ this.handler = handlerCreator.apply(this.logger);
+ this.setConnectionFactory(jmsFactory);
+ this.setErrorHandler(this);
+ this.setConcurrency(concurrentConsumers);
+ this.setDestination(destination);
+ this.setMessageListener(this);
+ }
+
+ @Override
+ public void onMessage(final Message message) {
+ try {
+ this.handler.onMessage(message);
+ } catch (final IdemponentRetryException e) {
+ // we are in non-transactional wonderland but the method is idempotent so we throw the message into spring and redeliver the
+ // message or send to DLQ!
+ throw e;
+ } catch (final Exception e) {
+ // we are in non-transactional wonderland so we catch the exception which leads to a request without a response.
+ this.logger.error("Exception", e);
+ }
+ }
+
+ @Override
+ public void handleError(@NonNull final Throwable e) {
+ // this method is called by spring if onMessage throws a RuntimeException (this means redevlivery, this means this exception will
+ // maybe logged several times or end in DLQ!)
+ this.logger.warn("Exception, retry!", e);
+ }
+
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/jms/InterconnectMessageSender.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/jms/InterconnectMessageSender.java
new file mode 100644
index 00000000..17489ffb
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/jms/InterconnectMessageSender.java
@@ -0,0 +1,205 @@
+package de.taimos.dvalin.interconnect.core.daemon.jms;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageSender;
+import de.taimos.dvalin.interconnect.core.daemon.exceptions.FrameworkErrors;
+import de.taimos.dvalin.interconnect.core.daemon.exceptions.FrameworkErrors.GenericError;
+import de.taimos.dvalin.interconnect.core.daemon.exceptions.UnexpectedTypeException;
+import de.taimos.dvalin.interconnect.core.daemon.model.InterconnectContext;
+import de.taimos.dvalin.interconnect.core.daemon.util.DaemonExceptionMapper;
+import de.taimos.dvalin.interconnect.model.FutureImpl;
+import de.taimos.dvalin.interconnect.model.InterconnectList;
+import de.taimos.dvalin.interconnect.model.InterconnectMapper;
+import de.taimos.dvalin.interconnect.model.InterconnectObject;
+import de.taimos.dvalin.interconnect.model.ivo.daemon.DaemonErrorIVO;
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.interconnect.model.service.DaemonErrorNumber;
+import de.taimos.dvalin.interconnect.model.service.DaemonScanner;
+import de.taimos.dvalin.jms.IJmsConnector;
+import de.taimos.dvalin.jms.exceptions.CreationException;
+import de.taimos.dvalin.jms.exceptions.CreationException.Source;
+import de.taimos.dvalin.jms.exceptions.InfrastructureException;
+import de.taimos.dvalin.jms.exceptions.SerializationException;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
+import de.taimos.dvalin.jms.model.JmsResponseContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.TextMessage;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+
+/**
+ * JMS Message sender.
+ *
+ * @author fzwirn
+ */
+@Component
+public final class InterconnectMessageSender implements IDaemonMessageSender {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ private final Executor executor = Executors.newCachedThreadPool();
+
+ private final IJmsConnector jmsConnector;
+ private final int tempQueueRetry;
+
+ /**
+ * @param jmsConnector JMS connector to use
+ * @param tempQueueRetry the deloy used before a retry
+ */
+ @Autowired
+ public InterconnectMessageSender(IJmsConnector jmsConnector, @Value("${interconnect.tempqueue.retry:100}") int tempQueueRetry) {
+ this.jmsConnector = jmsConnector;
+ this.tempQueueRetry = tempQueueRetry;
+ }
+
+ @Override
+ public void sendRequest(InterconnectContext interconnectContext) throws DaemonError, TimeoutException {
+ this.logger.debug("TextMessage send: {}", interconnectContext.getBody());
+ try {
+ this.jmsConnector.send(interconnectContext);
+ } catch (InfrastructureException e) {
+ if (this.checkForRetry(interconnectContext, e)) {
+ this.sendRequestRetry(interconnectContext);
+ return;
+ }
+ DaemonExceptionMapper.mapAndThrow(e);
+ } catch (SerializationException e) {
+ DaemonExceptionMapper.mapAndThrow(e);
+ }
+ }
+
+ private boolean checkForRetry(InterconnectContext so, InfrastructureException e) throws TimeoutException {
+ if (!so.isIdempotent()) {
+ return false;
+ }
+ if (!(e instanceof CreationException || e instanceof TimeoutException)) {
+ return false;
+ }
+ return !(e instanceof CreationException) ||
+ Source.DESTINATION.equals(((CreationException) e).getExceptionSource());
+ }
+
+ private void sendRequestRetry(InterconnectContext so) throws DaemonError, TimeoutException {
+ try {
+ this.logger.warn("Retrying message send to {} after {}ms", so.getDestinationName(), this.tempQueueRetry);
+ Thread.sleep(this.tempQueueRetry);
+ this.jmsConnector.send(so);
+ } catch (InfrastructureException | SerializationException ex) {
+ DaemonExceptionMapper.mapAndThrow(ex);
+ } catch (InterruptedException ex) {
+ this.logger.error("Interrupted while sending a retry message to {}", so.getDestinationName(), ex);
+ }
+ }
+
+ private JmsResponseContext extends Message> sendSyncRequestRetry(InterconnectContext so) throws DaemonError, TimeoutException {
+ try {
+ this.logger.warn("Retrying message send to {} after {}ms", so.getDestinationName(), this.tempQueueRetry);
+ Thread.sleep(this.tempQueueRetry);
+ return this.jmsConnector.request(so);
+ } catch (InfrastructureException | SerializationException ex) {
+ throw new DaemonError(FrameworkErrors.RETRY_FAILED_ERROR, DaemonExceptionMapper.map(ex));
+ } catch (InterruptedException ex) {
+ throw new DaemonError(FrameworkErrors.RETRY_FAILED_ERROR, ex);
+ }
+ }
+
+ @Override
+ public R syncRequest(InterconnectContext interconnectContext, Class responseClazz) throws DaemonError, TimeoutException {
+ try {
+ return this.request(interconnectContext, responseClazz);
+ } catch (final Exception e) {
+ DaemonExceptionMapper.mapAndThrow(e);
+ return null;
+ }
+ }
+
+ @Override
+ public Future asyncRequest(InterconnectContext interconnectContext, Class responseClazz) {
+ final FutureImpl f = new FutureImpl<>();
+ this.executor.execute(() -> {
+ try {
+ R value = this.request(interconnectContext, responseClazz);
+ f.set(value);
+ } catch (final Exception e) {
+ f.set(DaemonExceptionMapper.map(e));
+ }
+ });
+ return f;
+ }
+
+ private R request(InterconnectContext requestObject, Class responseClazz) throws DaemonError, InfrastructureException, SerializationException, UnexpectedTypeException {
+ JmsResponseContext extends Message> responseObject = null;
+ try {
+ responseObject = this.jmsConnector.request(requestObject);
+ } catch (SerializationException e) {
+ throw new RuntimeException(e);
+ } catch (InfrastructureException e) {
+ if (this.checkForRetry(requestObject, e)) {
+ responseObject = this.sendSyncRequestRetry(requestObject);
+ }
+ }
+
+ InterconnectObject ico = null;
+ if (responseObject != null && responseObject.getReceivedMessage() instanceof TextMessage) {
+ TextMessage receivedMessage = (TextMessage) responseObject.getReceivedMessage();
+ try {
+ ico = InterconnectMapper.fromJson(receivedMessage.getText());
+ } catch (IOException e) {
+ throw new SerializationException("Failed to read ico from received message.", e);
+ } catch (JMSException e) {
+ throw new InfrastructureException("Failed to read text of text message", e);
+ }
+ }
+ return InterconnectMessageSender.castToResponseClass(ico, responseClazz);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private static R castToResponseClass(final InterconnectObject ico, final Class responseClazz) throws DaemonError, UnexpectedTypeException {
+ if (ico instanceof DaemonErrorIVO) {
+ final DaemonErrorIVO de = (DaemonErrorIVO) ico;
+ final DaemonErrorNumber den = new GenericError(de.getNumber(), de.getDaemon());
+ throw new DaemonError(den, ((DaemonErrorIVO) ico).getMessage());
+ }
+ if (responseClazz.isArray() && (ico instanceof InterconnectList)) {
+ final InterconnectList list = (InterconnectList) ico;
+ final Object obj = Array.newInstance(responseClazz.getComponentType(), list.getElements().size());
+ return (R) list.getElements().toArray(DaemonScanner.object2Array(responseClazz.getComponentType(), obj));
+ } else if ((ico instanceof InterconnectList) && List.class.isAssignableFrom(responseClazz)) {
+ final InterconnectList list = (InterconnectList) ico;
+ return (R) list.getElements();
+ } else if (ico != null && responseClazz.isAssignableFrom(ico.getClass())) {
+ return (R) ico;
+ }
+ throw new UnexpectedTypeException("Response was not of type " + responseClazz.getSimpleName());
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/HandlingDuration.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/HandlingDuration.java
new file mode 100644
index 00000000..fd2a9184
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/HandlingDuration.java
@@ -0,0 +1,35 @@
+package de.taimos.dvalin.interconnect.core.daemon.model;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class HandlingDuration {
+ private final HandlingDurationType handlingDurationType;
+ private final long runtime;
+
+ /**
+ * @param handlingDurationType type of the handling duration
+ * @param runtime runtime of the handling
+ */
+ public HandlingDuration(HandlingDurationType handlingDurationType, long runtime) {
+ this.handlingDurationType = handlingDurationType;
+ this.runtime = runtime;
+ }
+
+ /**
+ * @return the handlingDurationType
+ */
+ public HandlingDurationType getHandlingDurationType() {
+ return this.handlingDurationType;
+ }
+
+ /**
+ * @return the runtime
+ */
+ public long getRuntime() {
+ return this.runtime;
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/HandlingDurationType.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/HandlingDurationType.java
new file mode 100644
index 00000000..ecbcf34c
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/HandlingDurationType.java
@@ -0,0 +1,13 @@
+package de.taimos.dvalin.interconnect.core.daemon.model;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public enum HandlingDurationType {
+ IN_TIME,
+ SLOW_RESPONSE,
+ TIMEOUT
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/InterconnectContext.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/InterconnectContext.java
new file mode 100644
index 00000000..dc13ecf6
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/InterconnectContext.java
@@ -0,0 +1,162 @@
+package de.taimos.dvalin.interconnect.core.daemon.model;
+
+import com.google.common.base.Preconditions;
+import de.taimos.dvalin.interconnect.model.InterconnectMapper;
+import de.taimos.dvalin.interconnect.model.InterconnectObject;
+import de.taimos.dvalin.jms.exceptions.InfrastructureException;
+import de.taimos.dvalin.jms.model.JmsContext;
+import de.taimos.dvalin.jms.model.JmsTarget;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class InterconnectContext extends JmsContext {
+
+ /**
+ * name of the message header to specify interconnect request UUID
+ */
+ public static final String HEADER_REQUEST_UUID = "InterconnectRequestUUID";
+
+ /**
+ * name of the message header to specify interconnect ICO class
+ */
+ public static final String HEADER_ICO_CLASS = "InterconnectICOClass";
+
+ public static class InterconnectContextBuilder extends AJmsContextBuilder {
+
+ private UUID uuid = UUID.randomUUID();
+ private InterconnectObject requestICO;
+ private boolean idempotent = false;
+
+ /**
+ * @param original context to create a new builder from
+ */
+ public InterconnectContextBuilder(JmsContext original) {
+ super(original);
+ }
+
+ /**
+ * Default builder constructor
+ */
+ public InterconnectContextBuilder() {
+ }
+
+ /**
+ * @param uuid for the context
+ * @return builder
+ */
+ public InterconnectContextBuilder withUuid(UUID uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
+
+ /**
+ * @param idempotent is the context idempotent
+ * @return builder
+ */
+ public InterconnectContextBuilder withIdempotent(boolean idempotent) {
+ this.idempotent = idempotent;
+ return this;
+ }
+
+ /**
+ * @param requestICO for the context, will override the body with the content of the requestIco
+ * @return builder
+ * @throws InfrastructureException in case of errors
+ */
+ public InterconnectContextBuilder withRequestICO(InterconnectObject requestICO) throws InfrastructureException {
+ this.requestICO = requestICO;
+ this.body = InterconnectContext.createBody(this.requestICO);
+ return this;
+ }
+
+ @Override
+ protected void validate() {
+ super.validate();
+ Preconditions.checkNotNull(this.uuid, "Universally unique identifier of the request");
+ }
+
+ @Override
+ @Nonnull
+ public InterconnectContext build() {
+ if ("true".equalsIgnoreCase(System.getProperty("jms.no-retry"))) {
+ this.idempotent = false;
+ }
+ if (this.uuid != null) {
+ this.headers.put(InterconnectContext.HEADER_REQUEST_UUID, this.uuid.toString());
+ }
+ if (this.requestICO != null) {
+ this.headers.put(InterconnectContext.HEADER_ICO_CLASS, this.requestICO.getClass().getName());
+ }
+ this.validate();
+ return new InterconnectContext(this);
+ }
+ }
+
+
+ private final InterconnectObject requestIco;
+ private final boolean idempotent;
+
+ protected InterconnectContext(InterconnectContextBuilder builder) {
+ super(builder);
+ this.requestIco = builder.requestICO;
+ this.idempotent = builder.idempotent;
+ }
+
+ /**
+ * @return the requestIco
+ */
+ public InterconnectObject getRequestIco() {
+ return this.requestIco;
+ }
+
+ /**
+ * @return the icoClass
+ */
+ public Class extends InterconnectObject> getIcoClass() {
+ return this.requestIco.getClass();
+ }
+
+ /**
+ * @return the idempotent
+ */
+ public boolean isIdempotent() {
+ return this.idempotent;
+ }
+
+ private static String createBody(InterconnectObject ico) throws InfrastructureException {
+ try {
+ return InterconnectMapper.toJson(ico);
+ } catch (final IOException e) {
+ throw new InfrastructureException("Failed to read message");
+ }
+ }
+
+ /**
+ * @param responseICO ico to use for the response
+ * @return a new response context with the responseIco, created from this context
+ * @throws InfrastructureException in case of errors
+ */
+ public InterconnectContext createResponseContext(InterconnectObject responseICO) throws InfrastructureException {
+ if (this.getReplyToDestination() != null) {
+ return new InterconnectContextBuilder(this)//
+ .withDestination(this.getReplyToDestination()) //
+ .withRequestICO(responseICO) //
+ .withIdempotent(false) //
+ .withTarget(JmsTarget.DESTINATION).build();
+ }
+ return new InterconnectContextBuilder(this)//
+ .withDestinationName(this.getReplyToQueueName()) //
+ .withRequestICO(responseICO) //
+ .withIdempotent(false) //
+ .withTarget(JmsTarget.QUEUE).build();
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/InterconnectResponseContext.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/InterconnectResponseContext.java
new file mode 100644
index 00000000..ed7ce40e
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/model/InterconnectResponseContext.java
@@ -0,0 +1,185 @@
+package de.taimos.dvalin.interconnect.core.daemon.model;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+
+import de.taimos.dvalin.interconnect.core.daemon.model.InterconnectContext.InterconnectContextBuilder;
+import de.taimos.dvalin.interconnect.model.InterconnectMapper;
+import de.taimos.dvalin.interconnect.model.InterconnectObject;
+import de.taimos.dvalin.interconnect.model.service.DaemonScanner.DaemonMethod;
+import de.taimos.dvalin.jms.exceptions.InfrastructureException;
+import de.taimos.dvalin.jms.model.JmsResponseContext;
+import de.taimos.dvalin.jms.model.JmsTarget;
+
+import javax.annotation.Nonnull;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+import java.io.IOException;
+
+/**
+ * Interconnect specific responseContext
+ *
+ * @author psigloch, fzwirn
+ */
+public final class InterconnectResponseContext extends JmsResponseContext {
+
+ private final InterconnectContext receivedContext;
+
+ private InterconnectObject responseICO;
+
+ private final long executionStartTime;
+ private DaemonMethod createResponseMethod;
+ private Long lastHandlingRuntime;
+
+
+ /**
+ * @param message received text message
+ * @param secure if this was a secure communication
+ * @param executionStartTime used by {@link InterconnectResponseContext#handlingDuration()} to calculation the duration of response handling, will use {@link System#currentTimeMillis()} if null
+ * @throws InfrastructureException in case of errors
+ */
+ public InterconnectResponseContext(@Nonnull TextMessage message, boolean secure, Long executionStartTime) throws InfrastructureException {
+ super(message);
+ this.executionStartTime = executionStartTime != null ? executionStartTime : System.currentTimeMillis();
+ final InterconnectObject receivedIco = this.extractIco();
+ InterconnectContextBuilder receivedContextBuilder = new InterconnectContextBuilder() //
+ .withTarget(JmsTarget.RECEPTION_CONTEXT).withSecure(secure) //
+ .withRequestICO(receivedIco) //
+ .withCorrelationId(this.extractCorreationId()) //
+ .withReplyToDestination(this.getReplyToDestination());
+ this.receivedContext = receivedContextBuilder.build();
+ }
+
+ private Destination getReplyToDestination() throws InfrastructureException {
+ try {
+ return this.getReceivedMessage().getJMSReplyTo();
+ } catch (JMSException e) {
+ throw new InfrastructureException("Failed to read reply to queue name from message");
+ }
+ }
+
+ private String extractCorreationId() throws InfrastructureException {
+ try {
+ return this.getReceivedMessage().getJMSCorrelationID();
+ } catch (JMSException e) {
+ throw new InfrastructureException("Failed to read correlation id from message");
+ }
+ }
+
+ private InterconnectObject extractIco() throws InfrastructureException {
+ try {
+ return InterconnectMapper.fromJson(this.getReceivedMessage().getText(), InterconnectObject.class);
+ } catch (final IOException | JMSException e) {
+ throw new InfrastructureException("Failed to create ico from message");
+ }
+ }
+
+ /**
+ * @return a response context, created from this context
+ * @throws InfrastructureException in case of errors
+ */
+ public InterconnectContext createResponseContext() throws InfrastructureException {
+ return this.receivedContext.createResponseContext(this.responseICO);
+ }
+
+ /**
+ * @return Request
+ */
+ public InterconnectContext getReceivedContext() {
+ return this.receivedContext;
+ }
+
+ /**
+ * @return the responseICO
+ */
+ public InterconnectObject getResponseICO() {
+ return this.responseICO;
+ }
+
+ /**
+ * @param responseICO the responseICO to set
+ */
+ public void setResponseICO(InterconnectObject responseICO) {
+ this.responseICO = responseICO;
+ }
+
+ /**
+ * @return the createResponseMethod
+ */
+ public DaemonMethod getCreateResponseMethod() {
+ return this.createResponseMethod;
+ }
+
+ /**
+ * @param createResponseMethod the createResponseMethod to set
+ */
+ public void setCreateResponseMethod(DaemonMethod createResponseMethod) {
+ this.createResponseMethod = createResponseMethod;
+ }
+
+
+ /**
+ * @return the lastHandlingRuntime, calculate if {@link #handlingDuration()} has not been called jet.
+ */
+ private Long getLastHandlingRuntime() {
+ if (this.lastHandlingRuntime == null) {
+ this.handlingDuration();
+ }
+ return this.lastHandlingRuntime;
+ }
+
+ /**
+ * @return a calculated {@link HandlingDuration} containing the runtime up to this point and a corresponding {@link HandlingDurationType}
+ */
+ public HandlingDuration handlingDuration() {
+ final long end = System.currentTimeMillis();
+ final long runtime = end - this.executionStartTime;
+ this.lastHandlingRuntime = runtime;
+ if (runtime > this.createResponseMethod.getTimeoutInMs()) {
+ return new HandlingDuration(HandlingDurationType.TIMEOUT, runtime);
+ } else if (runtime > (this.createResponseMethod.getTimeoutInMs() / 2L)) {
+ return new HandlingDuration(HandlingDurationType.SLOW_RESPONSE, runtime);
+ }
+ return new HandlingDuration(HandlingDurationType.IN_TIME, runtime);
+ }
+
+ /**
+ * @return a default timeout message for logging or exceptions
+ */
+ public String timeoutMessage() {
+ return "Response skipped because runtime " + this.getLastHandlingRuntime() + " ms was greater than timeout " +
+ this.getCreateResponseMethod().getTimeoutInMs() + " ms for " +
+ this.getCreateResponseMethod().getMethod().getName() + "(" +
+ this.getReceivedContext().getIcoClass().getSimpleName() + ")" + " with " +
+ de.taimos.dvalin.interconnect.model.InterconnectContext.getContext();
+ }
+
+ /**
+ * @return a default slow response message for logging or exceptions
+ */
+ public String slowResponseMessage() {
+ return "Slow response because runtime " + this.getLastHandlingRuntime() + " ms for " +
+ this.getCreateResponseMethod().getMethod().getName() + "(" +
+ this.getReceivedContext().getIcoClass().getSimpleName() + ")" + " with " +
+ de.taimos.dvalin.interconnect.model.InterconnectContext.getContext();
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/proxy/ADaemonProxyFactory.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/proxy/ADaemonProxyFactory.java
new file mode 100644
index 00000000..8c8ba620
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/proxy/ADaemonProxyFactory.java
@@ -0,0 +1,61 @@
+package de.taimos.dvalin.interconnect.core.daemon.proxy;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonProxyFactory;
+import de.taimos.dvalin.interconnect.core.daemon.model.InterconnectContext;
+import de.taimos.dvalin.interconnect.core.daemon.util.DaemonMethodInvocationHandler;
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.interconnect.model.service.IDaemon;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
+
+/**
+ * Copyright 2015 Taimos GmbH
+ *
+ *
+ * @author Thorsten Hoeger
+ */
+public abstract class ADaemonProxyFactory implements IDaemonProxyFactory {
+
+
+ /**
+ * @param interconnectContext context used for the send request
+ * @throws DaemonError with specific error code
+ * @throws TimeoutException in case of communication timeout
+ */
+ public abstract void sendRequest(InterconnectContext interconnectContext) throws DaemonError, TimeoutException;
+
+
+ /**
+ * @param interconnectContext context used for the send request
+ * @param responseClazz class of the expected response
+ * @param response class
+ * @return a response to the request
+ * @throws DaemonError with specific error code
+ * @throws TimeoutException in case of communication timeout
+ */
+ public abstract R syncRequest(InterconnectContext interconnectContext, Class responseClazz) throws DaemonError, TimeoutException;
+
+ @Override
+ public final D create(final Class daemon) {
+ return DaemonMethodInvocationHandler.createProxy(daemon, this);
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/proxy/DefaultDaemonProxyFactory.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/proxy/DefaultDaemonProxyFactory.java
new file mode 100644
index 00000000..72b52411
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/proxy/DefaultDaemonProxyFactory.java
@@ -0,0 +1,65 @@
+package de.taimos.dvalin.interconnect.core.daemon.proxy;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonMessageSender;
+import de.taimos.dvalin.interconnect.core.daemon.model.InterconnectContext;
+import de.taimos.dvalin.interconnect.core.daemon.util.DaemonExceptionMapper;
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Default daemon proxy factory
+ *
+ * @author psigloch, fzwirn
+ */
+@Component
+public class DefaultDaemonProxyFactory extends ADaemonProxyFactory {
+
+
+ private final IDaemonMessageSender messageSender;
+
+
+ /**
+ * @param aMessageSender Message sender
+ */
+ @Autowired
+ public DefaultDaemonProxyFactory(final IDaemonMessageSender aMessageSender) {
+ super();
+ this.messageSender = aMessageSender;
+ }
+
+ @Override
+ public void sendRequest(InterconnectContext interconnectContext) throws DaemonError, TimeoutException {
+ try {
+ this.messageSender.sendRequest(interconnectContext);
+ } catch (Exception e) {
+ DaemonExceptionMapper.mapAndThrow(e);
+ }
+ }
+
+ @Override
+ public R syncRequest(InterconnectContext interconnectContext, Class responseClazz) throws DaemonError, TimeoutException {
+ return this.messageSender.syncRequest(interconnectContext, responseClazz);
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/DaemonExceptionMapper.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/DaemonExceptionMapper.java
new file mode 100644
index 00000000..f5e8c5a8
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/DaemonExceptionMapper.java
@@ -0,0 +1,122 @@
+package de.taimos.dvalin.interconnect.core.daemon.util;
+
+import de.taimos.dvalin.interconnect.core.daemon.exceptions.FrameworkErrors;
+import de.taimos.dvalin.interconnect.core.daemon.exceptions.UnexpectedTypeException;
+import de.taimos.dvalin.interconnect.model.service.DaemonError;
+import de.taimos.dvalin.interconnect.model.service.DaemonErrorNumber;
+import de.taimos.dvalin.jms.exceptions.CommunicationFailureException;
+import de.taimos.dvalin.jms.exceptions.CommunicationFailureException.CommunicationError;
+import de.taimos.dvalin.jms.exceptions.CreationException;
+import de.taimos.dvalin.jms.exceptions.CreationException.Source;
+import de.taimos.dvalin.jms.exceptions.InfrastructureException;
+import de.taimos.dvalin.jms.exceptions.MessageCryptoException;
+import de.taimos.dvalin.jms.exceptions.SerializationException;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class DaemonExceptionMapper {
+
+
+ /**
+ * Calls {@link DaemonExceptionMapper#map(Exception)} and throws the result.
+ *
+ * @param e original exception
+ * @throws DaemonError with a {@link DaemonErrorNumber} corresponding to the original exception.
+ * @throws TimeoutException are not mapped
+ */
+ public static void mapAndThrow(Exception e) throws DaemonError, TimeoutException {
+ Exception exception = DaemonExceptionMapper.map(e);
+ if (e instanceof DaemonError) {
+ throw (DaemonError) exception;
+ } else if (e instanceof TimeoutException) {
+ throw (TimeoutException) exception;
+ } else {
+ throw new UnsupportedOperationException("Failed to map exception", e);
+ }
+ }
+
+ /**
+ * @param e original exception
+ * @return {@link DaemonError} with a {@link DaemonErrorNumber} corresponding to the original exception.
+ * {@link TimeoutException} are returned without mapping them.
+ */
+ public static Exception map(Exception e) {
+ if (e instanceof DaemonError) {
+ return e;
+ }
+ if (e instanceof UnexpectedTypeException) {
+ return new DaemonError(FrameworkErrors.UNEXPECTED_TYPE_ERROR, e);
+ }
+ if (e instanceof TimeoutException) {
+ return e;
+ }
+ if (e instanceof InfrastructureException) {
+ return DaemonExceptionMapper.handleInfrastructureException((InfrastructureException) e);
+ }
+ if (e instanceof SerializationException) {
+ return DaemonExceptionMapper.handleSerializationException((SerializationException) e);
+ }
+ return new DaemonError(FrameworkErrors.FRAMEWORK_ERROR, e);
+ }
+
+ private static Exception handleInfrastructureException(InfrastructureException e) {
+ if (e instanceof CommunicationFailureException) {
+ return DaemonExceptionMapper.handleCommunicationFailureException((CommunicationFailureException) e);
+ }
+ if (e instanceof CreationException) {
+ return DaemonExceptionMapper.handleCreationException((CreationException) e);
+ }
+
+ return new DaemonError(FrameworkErrors.FRAMEWORK_ERROR, e);
+ }
+
+ private static Exception handleCommunicationFailureException(CommunicationFailureException e) {
+ if (CommunicationError.SEND.equals(e.getCommunicationError())) {
+ return new DaemonError(FrameworkErrors.SEND_ERROR, e);
+ }
+ if (CommunicationError.RECEIVE.equals(e.getCommunicationError())) {
+ return new DaemonError(FrameworkErrors.RECEIVE_ERROR, e);
+ }
+ if (CommunicationError.INVALID_RESPONSE.equals(e.getCommunicationError())) {
+ return new DaemonError(FrameworkErrors.INVALID_RESPONSE_ERROR, e);
+ }
+ return new DaemonError(FrameworkErrors.FRAMEWORK_ERROR, e);
+ }
+
+ private static Exception handleCreationException(CreationException e) {
+ if (Source.SESSION.equals(e.getExceptionSource())) {
+ return new DaemonError(FrameworkErrors.SESSION_CREATION_ERROR, e);
+ }
+ if (Source.CONNECTION.equals(e.getExceptionSource())) {
+ return new DaemonError(FrameworkErrors.CONNECT_CREATION_ERROR, e);
+ }
+ if (Source.DESTINATION.equals(e.getExceptionSource())) {
+ return new DaemonError(FrameworkErrors.DESTINATION_CREATION_ERROR, e);
+ }
+ if (Source.REPLY_TO_DESTINATION.equals(e.getExceptionSource())) {
+ return new DaemonError(FrameworkErrors.REPLY_TO_DESTINATION_CREATION_ERROR, e);
+ }
+ if (Source.CONSUMER.equals(e.getExceptionSource())) {
+ return new DaemonError(FrameworkErrors.CONSUMER_CREATION_ERROR, e);
+ }
+ if (Source.PRODUCER.equals(e.getExceptionSource())) {
+ return new DaemonError(FrameworkErrors.PRODUCER_CREATION_ERROR, e);
+ }
+ if (Source.FAILED_TO_CREATE_MESSAGE.equals(e.getExceptionSource())) {
+ return new DaemonError(FrameworkErrors.MESSAGE_CREATION_ERROR, e);
+ }
+ return new DaemonError(FrameworkErrors.FRAMEWORK_ERROR, e);
+ }
+
+ private static DaemonError handleSerializationException(SerializationException e) {
+ if (e instanceof MessageCryptoException) {
+ return new DaemonError(FrameworkErrors.MESSAGE_CRYPTO_ERROR, e);
+ }
+ return new DaemonError(FrameworkErrors.MESSAGE_SERIALIZATION, e);
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/DaemonMethodInvocationHandler.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/DaemonMethodInvocationHandler.java
new file mode 100644
index 00000000..51477abe
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/DaemonMethodInvocationHandler.java
@@ -0,0 +1,96 @@
+package de.taimos.dvalin.interconnect.core.daemon.util;
+
+import de.taimos.dvalin.interconnect.core.daemon.model.InterconnectContext;
+import de.taimos.dvalin.interconnect.core.daemon.model.InterconnectContext.InterconnectContextBuilder;
+import de.taimos.dvalin.interconnect.core.daemon.proxy.ADaemonProxyFactory;
+import de.taimos.dvalin.interconnect.model.InterconnectObject;
+import de.taimos.dvalin.interconnect.model.ivo.daemon.VoidIVO;
+import de.taimos.dvalin.interconnect.model.service.Daemon;
+import de.taimos.dvalin.interconnect.model.service.DaemonScanner;
+import de.taimos.dvalin.interconnect.model.service.DaemonScanner.DaemonMethod;
+import de.taimos.dvalin.interconnect.model.service.IDaemon;
+import de.taimos.dvalin.jms.exceptions.InfrastructureException;
+import de.taimos.dvalin.jms.model.JmsTarget;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class DaemonMethodInvocationHandler implements InvocationHandler {
+
+ private final String queueName;
+ private final ADaemonProxyFactory aDaemonProxyFactory;
+
+ private DaemonMethodInvocationHandler(ADaemonProxyFactory aDaemonProxyFactory, String queueName) {
+ this.queueName = queueName;
+ this.aDaemonProxyFactory = aDaemonProxyFactory;
+ }
+
+ /**
+ * @param daemonInterface daemon interface class
+ * @param aDaemonProxyFactory proxy factory
+ * @param interface for which the proxy will be created
+ * @return a proxy for the {@code daemonInterface}, using the {@code aDaemonProxyFactory}
+ */
+ @SuppressWarnings("unchecked")
+ public static D createProxy(Class daemonInterface, ADaemonProxyFactory aDaemonProxyFactory) {
+ if (!daemonInterface.isAnnotationPresent(Daemon.class)) {
+ throw new IllegalArgumentException("Daemon interface has no @Daemon annotation");
+ }
+
+ String localQueueName = daemonInterface.getAnnotation(Daemon.class).name() + ".request";
+
+ return (D) Proxy.newProxyInstance(aDaemonProxyFactory.getClass().getClassLoader(),
+ new Class>[]{daemonInterface}, new DaemonMethodInvocationHandler(aDaemonProxyFactory, localQueueName));
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ try {
+ final DaemonScanner.DaemonMethod dm = DaemonScanner.scan(method);
+ if (dm == null) {
+ throw new Exception("Method " + method.getName() + " is not a daemon method.");
+ }
+
+ InterconnectContext sendContext = this.createSendContext(args, dm);
+
+ if (dm.getType() == DaemonScanner.Type.voit) {
+ this.aDaemonProxyFactory.sendRequest(sendContext);
+ return null;
+ }
+
+ final Class> responseClass = DaemonMethodInvocationHandler.getResponseClass(method);
+ return this.aDaemonProxyFactory.syncRequest(sendContext, responseClass);
+ } catch (Exception e) {
+ throw DaemonExceptionMapper.map(e);
+ }
+ }
+
+ private static Class> getResponseClass(Method method) {
+ final Class> responseClass;
+ if (method.getReturnType().equals(Void.TYPE)) {
+ responseClass = VoidIVO.class;
+ } else {
+ responseClass = method.getReturnType();
+ }
+ return responseClass;
+ }
+
+ private InterconnectContext createSendContext(Object[] args, DaemonMethod dm) throws InfrastructureException {
+ return new InterconnectContextBuilder() //
+ .withUuid(de.taimos.dvalin.interconnect.model.InterconnectContext.getUuid()) //
+ .withTarget(JmsTarget.QUEUE) //
+ .withDestinationName(this.queueName) //
+ .withRequestICO((InterconnectObject) args[0]) //
+ .withTimeToLive(dm.getTimeoutInMs(), TimeUnit.MILLISECONDS) //
+ .withReceiveTimeout(dm.getTimeoutInMs(), TimeUnit.MILLISECONDS) //
+ .withSecure(dm.isSecure()).withIdempotent(dm.isIdempotent()).build();
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/DaemonMethodRegistry.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/DaemonMethodRegistry.java
new file mode 100644
index 00000000..5fe3a1dd
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/DaemonMethodRegistry.java
@@ -0,0 +1,79 @@
+package de.taimos.dvalin.interconnect.core.daemon.util;
+
+import de.taimos.dvalin.interconnect.model.InterconnectObject;
+import de.taimos.dvalin.interconnect.model.service.DaemonScanner;
+import de.taimos.dvalin.interconnect.model.service.DaemonScanner.DaemonMethod;
+import de.taimos.dvalin.interconnect.model.service.IDaemonHandler;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Copyright 2022 Taimos GmbH
+ *
+ *
+ * @author psigloch
+ */
+public class DaemonMethodRegistry {
+
+ private final Map, RegistryEntry> registry;
+
+ /**
+ * @param aHandlerClazzes all handler classes
+ */
+ public DaemonMethodRegistry(final Collection> aHandlerClazzes) {
+ final Map, RegistryEntry> reg = new HashMap<>();
+ for (Class extends IDaemonHandler> aHandlerClazz : aHandlerClazzes) {
+ for (final DaemonScanner.DaemonMethod re : DaemonScanner.scan(aHandlerClazz)) {
+ reg.put(re.getRequest(), new RegistryEntry(aHandlerClazz, re));
+ }
+ }
+ this.registry = Collections.unmodifiableMap(reg);
+ }
+
+ /**
+ * @param icoClass the interconnect object class
+ * @return the registry entry
+ */
+ public RegistryEntry get(Class extends InterconnectObject> icoClass) {
+ return this.registry.get(icoClass);
+ }
+
+ /**
+ * @param icoClass the interconnect object class
+ * @return the daemon method
+ */
+ public DaemonMethod getMethod(Class extends InterconnectObject> icoClass) {
+ RegistryEntry registryEntry = this.registry.get(icoClass);
+ if (registryEntry == null) {
+ return null;
+ }
+ return registryEntry.getMethod();
+ }
+
+ public static class RegistryEntry {
+ private final Class extends IDaemonHandler> aHandlerClazz;
+ private final DaemonMethod method;
+
+ RegistryEntry(Class extends IDaemonHandler> aHandlerClazz, DaemonMethod method) {
+ this.aHandlerClazz = aHandlerClazz;
+ this.method = method;
+ }
+
+ /**
+ * @return the aHandlerClazz
+ */
+ public Class extends IDaemonHandler> getHandlerClazz() {
+ return this.aHandlerClazz;
+ }
+
+ /**
+ * @return the method
+ */
+ public DaemonMethod getMethod() {
+ return this.method;
+ }
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/InterconnectBeanPostProcessor.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/InterconnectBeanPostProcessor.java
new file mode 100644
index 00000000..5a395aff
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/InterconnectBeanPostProcessor.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package de.taimos.dvalin.interconnect.core.daemon.util;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+
+import de.taimos.dvalin.interconnect.core.daemon.Interconnect;
+import de.taimos.dvalin.interconnect.core.daemon.proxy.DefaultDaemonProxyFactory;
+import de.taimos.dvalin.interconnect.model.service.IDaemon;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.PropertyValues;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.annotation.InjectionMetadata;
+import org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement;
+import org.springframework.beans.factory.config.DependencyDescriptor;
+import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
+import org.springframework.core.BridgeMethodResolver;
+import org.springframework.core.MethodParameter;
+import org.springframework.lang.NonNull;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+import java.beans.PropertyDescriptor;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.LinkedList;
+
+/**
+ * @author thoeger
+ */
+@Component
+@SuppressWarnings("serial")
+public class InterconnectBeanPostProcessor
+ implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
+
+ private transient DefaultDaemonProxyFactory proxyFactory;
+
+ @Override
+ public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
+ Assert.notNull(beanFactory, "BeanFactory must not be null");
+ this.proxyFactory = beanFactory.getBean(DefaultDaemonProxyFactory.class);
+ }
+
+ @Override
+ public PropertyValues postProcessProperties(@NonNull PropertyValues pvs, Object bean, @NonNull String beanName) throws BeansException {
+ InjectionMetadata metadata = this.buildResourceMetadata(bean.getClass());
+ try {
+ metadata.inject(bean, beanName, pvs);
+ } catch (Throwable ex) {
+ throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
+ }
+ return pvs;
+ }
+
+ @Override
+ @Deprecated
+ public PropertyValues postProcessPropertyValues(@NonNull PropertyValues pvs, @NonNull PropertyDescriptor[] pds, @NonNull Object bean, @NonNull String beanName) throws BeansException {
+ return this.postProcessProperties(pvs, bean, beanName);
+ }
+
+ private InjectionMetadata buildResourceMetadata(Class> clazz) {
+ LinkedList elements = new LinkedList<>();
+ Class> targetClass = clazz;
+
+ do {
+ LinkedList currElements = new LinkedList<>();
+ currElements.addAll(this.getFieldInjections(targetClass));
+ currElements.addAll(this.getMethodInjections(clazz, targetClass));
+ elements.addAll(0, currElements);
+ targetClass = targetClass.getSuperclass();
+ } while ((targetClass != null) && (targetClass != Object.class));
+
+ return new InjectionMetadata(clazz, elements);
+ }
+
+ private LinkedList getFieldInjections(Class> targetClass) {
+ LinkedList currElements = new LinkedList<>();
+ for (Field field : targetClass.getDeclaredFields()) {
+ if (field.isAnnotationPresent(Interconnect.class)) {
+ if (Modifier.isStatic(field.getModifiers())) {
+ throw new IllegalStateException("@Interconnect annotation is not supported on static fields");
+ }
+ currElements.add(new InterconnectElement(field, null));
+ }
+ }
+ return currElements;
+ }
+
+ private LinkedList getMethodInjections(Class> clazz, Class> targetClass) {
+ LinkedList currElements = new LinkedList<>();
+ for (Method method : targetClass.getDeclaredMethods()) {
+ Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
+ if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
+ continue;
+ }
+ if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
+ if (bridgedMethod.isAnnotationPresent(Interconnect.class)) {
+ if (Modifier.isStatic(method.getModifiers())) {
+ throw new IllegalStateException("@Interconnect annotation is not supported on static methods");
+ }
+ if (method.getParameterTypes().length != 1) {
+ throw new IllegalStateException(
+ "@Interconnect annotation requires a single-arg method: " + method);
+ }
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
+ currElements.add(new InterconnectElement(method, pd));
+ }
+ }
+ }
+ return currElements;
+ }
+
+
+ /**
+ * Class representing injection information about an annotated field
+ * or setter method, supporting the @Interconnect annotation.
+ */
+ private class InterconnectElement extends InjectionMetadata.InjectedElement {
+
+ public InterconnectElement(Member member, PropertyDescriptor pd) {
+ super(member, pd);
+ }
+
+ private DependencyDescriptor getDependencyDescriptor() {
+ if (this.isField) {
+ return new DependencyDescriptor((Field) this.member, true);
+ }
+ return new DependencyDescriptor(new MethodParameter((Method) this.member, 0), true);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Object getResourceToInject(@NonNull Object target, String requestingBeanName) {
+ Class> dependencyType = this.getDependencyDescriptor().getDependencyType();
+ if (!IDaemon.class.isAssignableFrom(dependencyType)) {
+ throw new RuntimeException(
+ "Field has to be of type IDaemon but was of type " + dependencyType.getCanonicalName());
+ }
+ return InterconnectBeanPostProcessor.this.proxyFactory.create((Class extends IDaemon>) dependencyType);
+ }
+ }
+
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/PagingController.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/PagingController.java
new file mode 100644
index 00000000..db62e172
--- /dev/null
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/daemon/util/PagingController.java
@@ -0,0 +1,182 @@
+package de.taimos.dvalin.interconnect.core.daemon.util;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentHashMap;
+
+import de.taimos.dvalin.interconnect.core.daemon.IDaemonProxyFactory;
+import de.taimos.dvalin.interconnect.model.ivo.IPageable;
+import de.taimos.dvalin.interconnect.model.ivo.IPageableBuilder;
+import de.taimos.dvalin.interconnect.model.ivo.IVO;
+import de.taimos.dvalin.interconnect.model.ivo.util.IVOQueryResultIVO_v1;
+import de.taimos.dvalin.interconnect.model.service.IDaemon;
+
+
+/**
+ * You can give me a Request-IVO and an IDaemon interface and I will get all the pages for that request as an Iterable if the result is an
+ * IVOQueryResultIVO_v1. Be sure to type me according to the return of the Daemon otherwise I will produce a class cast
+ * exception at runtime.
+ * New Pages are fetched on hasNext() call so be prepared that a call to hasNext() will block all this.limit items for a while.
+ *
+ * @param IVO type
+ * @author thoeger
+ */
+public final class PagingController implements Iterator {
+
+ static {
+ try {
+ NO_SUCH_METHOD = String.class.getMethod("toString");
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static final Method NO_SUCH_METHOD;
+ /**
+ * Map : to method
+ */
+ private static final ConcurrentHashMap METHOD_CACHE = new ConcurrentHashMap<>();
+
+ private final IDaemonProxyFactory proxyFactory;
+ private final Class extends IDaemon> daemonClass;
+ private final int limit;
+ private final IPageable initialRequest;
+ private int nextOffset = 0;
+ private int batchIndex = -1;
+ private List batch;
+
+
+ /**
+ * @param proxyFactory Proxy factory
+ * @param daemonClass Daemon
+ * @param limit Limit
+ * @param initialRequest Initial request (offset and limit fields are adjusted!)
+ */
+ public PagingController(final IDaemonProxyFactory proxyFactory, final Class extends IDaemon> daemonClass, final int limit, final IPageable initialRequest) {
+ this.proxyFactory = proxyFactory;
+ this.daemonClass = daemonClass;
+ this.limit = limit;
+ this.initialRequest = initialRequest;
+ }
+
+ /**
+ * @param proxyFactory Proxy factory
+ * @param daemonClass Daemon
+ * @param initialRequest Initial request (offset and limit fields are adjusted!)
+ */
+ public PagingController(final IDaemonProxyFactory proxyFactory, final Class extends IDaemon> daemonClass, final IPageable initialRequest) {
+ this(proxyFactory, daemonClass, 100, initialRequest);
+ }
+
+ private Method scanProxyMethods(final Object proxy) {
+ for (final Method method : proxy.getClass().getDeclaredMethods()) {
+ if (method.getParameterTypes().length == 1) {
+ if (method.getParameterTypes()[0].equals(this.initialRequest.getClass())) {
+ return method;
+ }
+ }
+ }
+ return null;
+ }
+
+ private Method extractProxyMethod(final IDaemon proxy) {
+ final String cachekey =
+ proxy.getClass().getCanonicalName() + ":" + this.initialRequest.getClass().getCanonicalName();
+ final Method cached = PagingController.METHOD_CACHE.get(cachekey);
+ if (cached != null) {
+ if (cached.equals(PagingController.NO_SUCH_METHOD)) {
+ throw new RuntimeException("proxy method not found for " + this.initialRequest.getClass());
+ }
+ return cached;
+ }
+ final Method method = this.scanProxyMethods(proxy);
+ if (method == null) {
+ PagingController.METHOD_CACHE.putIfAbsent(cachekey, PagingController.NO_SUCH_METHOD);
+ throw new RuntimeException("proxy method not found for " + this.initialRequest.getClass());
+ }
+ method.setAccessible(true);
+ PagingController.METHOD_CACHE.putIfAbsent(cachekey, method);
+ return method;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if ((this.batch != null) &&
+ (this.batch.isEmpty())) { // we are at the end of the query because we have an empty result
+ return false;
+ }
+ final int nextBatchIndex = this.batchIndex + 1;
+ if ((this.batch == null) ||
+ (nextBatchIndex == this.batch.size())) { // we are at the end of the batch -> fetch next batch
+ if ((this.batch != null) && (this.batch.size() != this.limit)) { // we are at the end of the query
+ return false;
+ }
+
+ // create request IVO
+ final Object request;
+ try {
+ final IPageableBuilder b = this.initialRequest.createPageableBuilder();
+ b.withOffset(this.nextOffset);
+ b.withLimit(this.limit);
+ request = b.build();
+ } catch (final Exception e) {
+ throw new RuntimeException("Can not build from IVO", e);
+ }
+
+ // execute query
+ final IVOQueryResultIVO_v1 list;
+ try {
+ final IDaemon proxy = this.proxyFactory.create(this.daemonClass);
+ final Method proxyMethod = this.extractProxyMethod(proxy);
+ list = (IVOQueryResultIVO_v1) proxyMethod.invoke(proxy, request);
+ } catch (final Exception e) {
+ throw new RuntimeException("Can not get next elements", e);
+ }
+
+ // update batch
+ this.nextOffset += this.limit;
+ this.batchIndex = -1;
+ this.batch = list.getElements();
+
+ // check if we are at the end of the query
+ return !this.batch.isEmpty();
+ }
+ return true;
+ }
+
+ @Override
+ public E next() {
+ if (!this.hasNext()) {
+ throw new NoSuchElementException();
+ }
+ this.batchIndex++;
+ return this.batch.get(this.batchIndex);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/event/EventHandler.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/event/EventHandler.java
index e3da3bdd..48fafb90 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/event/EventHandler.java
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/event/EventHandler.java
@@ -10,7 +10,11 @@
import java.lang.annotation.Target;
/**
+ * Annotation to mark a class,
+ * that extends {@link de.taimos.dvalin.interconnect.model.service.IEventHandler} as an event handler,
+ * to be picked up by {@link EventMessageListener}.
*
+ * @author psigloch
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
diff --git a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/event/EventMessageListener.java b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/event/EventMessageListener.java
index 95f4af00..81fed2f6 100644
--- a/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/event/EventMessageListener.java
+++ b/interconnect/core/src/main/java/de/taimos/dvalin/interconnect/core/event/EventMessageListener.java
@@ -20,14 +20,15 @@
* #L%
*/
-import de.taimos.daemon.spring.annotations.ProdComponent;
-import de.taimos.dvalin.interconnect.core.MessageConnector;
import de.taimos.dvalin.interconnect.model.InterconnectMapper;
import de.taimos.dvalin.interconnect.model.InterconnectObject;
import de.taimos.dvalin.interconnect.model.event.EventDomain;
import de.taimos.dvalin.interconnect.model.event.IEvent;
import de.taimos.dvalin.interconnect.model.service.IEventHandler;
-import org.apache.activemq.command.ActiveMQQueue;
+import de.taimos.dvalin.jms.DvalinConnectionFactory;
+import de.taimos.dvalin.jms.IDestinationService;
+import de.taimos.dvalin.jms.crypto.ICryptoService;
+import de.taimos.dvalin.jms.model.JmsTarget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,30 +38,33 @@
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.listener.MessageListenerContainer;
+import org.springframework.stereotype.Component;
import org.springframework.util.ErrorHandler;
+import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
-import javax.jms.ConnectionFactory;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
-import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
-@ProdComponent("eventMessageListener")
+/**
+ * Event listener
+ *
+ * @author psigloch, fzwirn
+ */
+@Component("eventMessageListener")
public class EventMessageListener implements MessageListener, ErrorHandler {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${interconnect.jms.consumers:2-8}")
private String consumers;
-
@Value("${serviceName}")
private String serviceName;
-
@Value("${interconnect.jms.virtualtopic.prefix:VirtualTopic}")
private String virtualTopicPrefix;
@Value("${interconnect.jms.virtualtopic.consumerprefix:Consumer}")
@@ -68,30 +72,38 @@ public class EventMessageListener implements MessageListener, ErrorHandler {
@Autowired
@Qualifier("DvalinConnectionFactory")
- private ConnectionFactory jmsFactory;
+ private DvalinConnectionFactory jmsFactory;
@Autowired
private ApplicationContext applicationContext;
+ @Autowired
+ private IDestinationService destinationService;
+ @Autowired
+ private ICryptoService cryptoService;
- private Set eventHandlers;
+ private Set> eventHandlers;
private Set listeners;
- /** */
+ /**
+ *
+ */
public EventMessageListener() {
super();
}
- /** */
+ /**
+ *
+ */
@PostConstruct
public void initEventListeners() {
this.listeners = new HashSet<>();
this.eventHandlers = new HashSet<>();
- for(Object o : this.applicationContext.getBeansWithAnnotation(EventHandler.class).values()) {
- if(o instanceof IEventHandler) {
- this.eventHandlers.add((IEventHandler) o);
+ for (Object o : this.applicationContext.getBeansWithAnnotation(EventHandler.class).values()) {
+ if (o instanceof IEventHandler) {
+ this.eventHandlers.add((IEventHandler extends IEvent>) o);
}
}
- for(String domain : this.getDomains()) {
+ for (String domain : this.getDomains()) {
this.logger.info("Registered EventListener for topic {}", domain);
DefaultMessageListenerContainer dmlc = this.createQueueListener(domain);
this.listeners.add(dmlc);
@@ -99,49 +111,53 @@ public void initEventListeners() {
}
- /** */
+ /**
+ *
+ */
@PreDestroy
public void stopEventListeners() {
- for(MessageListenerContainer listener : this.listeners) {
+ for (MessageListenerContainer listener : this.listeners) {
listener.stop();
}
}
@Override
+ @SuppressWarnings({"rawtypes", "unchecked"})
public void onMessage(Message message) {
try {
- if(message instanceof TextMessage) {
- final TextMessage textMessage = (TextMessage) message;
+ if (message instanceof TextMessage) {
+ TextMessage textMessage = (TextMessage) message;
this.logger.debug("TextMessage received: {}", textMessage.getText());
- final boolean secure = MessageConnector.isMessageSecure(textMessage);
- if(secure) {
- MessageConnector.decryptMessage(textMessage);
+ final boolean secure = this.cryptoService.isMessageSecure(textMessage);
+ if (secure) {
+ textMessage = (TextMessage) this.cryptoService.decryptMessage(textMessage);
}
- final InterconnectObject eventIn = InterconnectMapper.fromJson(textMessage.getText(), InterconnectObject.class);
- for(IEventHandler eventHandler : this.eventHandlers) {
- if(eventHandler != null && eventIn.getClass().isAssignableFrom(eventHandler.getEventType())) {
+ InterconnectObject eventIn = InterconnectMapper.fromJson(textMessage.getText(),
+ InterconnectObject.class);
+ for (IEventHandler eventHandler : this.eventHandlers) {
+ if (eventHandler != null && eventIn.getClass().isAssignableFrom(eventHandler.getEventType())) {
eventHandler.handleEvent((IEvent) eventIn);
}
}
}
- } catch(final Exception e) {
+ } catch (final Exception e) {
// we are in non transactional wonderland so we catch the exception which leads to a request without a response.
this.logger.error("Exception", e);
}
}
@Override
- public void handleError(Throwable throwable) {
+ public void handleError(@Nonnull Throwable throwable) {
this.logger.warn("An error during event handling occured", throwable);
}
private DefaultMessageListenerContainer createQueueListener(String domain) {
- ActiveMQQueue virtualTopic = new ActiveMQQueue(this.consumerPrefix + "." + this.serviceName + "." + this.virtualTopicPrefix + "." + domain);
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(this.jmsFactory);
dmlc.setErrorHandler(this);
dmlc.setConcurrency(this.consumers);
- dmlc.setDestination(virtualTopic);
+ String queueName = this.consumerPrefix + "." + this.serviceName + "." + this.virtualTopicPrefix + "." + domain;
+ dmlc.setDestination(this.destinationService.createDestination(JmsTarget.QUEUE, queueName));
dmlc.setMessageListener(this);
dmlc.afterPropertiesSet();
dmlc.start();
@@ -150,16 +166,17 @@ private DefaultMessageListenerContainer createQueueListener(String domain) {
private Collection getDomains() {
Set result = new HashSet<>();
- if(this.eventHandlers == null || this.eventHandlers.isEmpty()) {
+ if (this.eventHandlers == null || this.eventHandlers.isEmpty()) {
return result;
}
- for(IEventHandler eventHandler : this.eventHandlers) {
- if(eventHandler == null || eventHandler.getEventType() == null) {
+ for (IEventHandler extends IEvent> eventHandler : this.eventHandlers) {
+ if (eventHandler == null || eventHandler.getEventType() == null) {
continue;
}
- Annotation domainAnnotation = AnnotationUtils.findAnnotation(eventHandler.getEventType(), EventDomain.class);
- if(domainAnnotation != null && !((EventDomain) domainAnnotation).value().isEmpty()) {
- result.add(((EventDomain) domainAnnotation).value());
+ EventDomain domainAnnotation = AnnotationUtils.findAnnotation(eventHandler.getEventType(),
+ EventDomain.class);
+ if (domainAnnotation != null && !domainAnnotation.value().isEmpty()) {
+ result.add(domainAnnotation.value());
}
}
return result;
diff --git a/interconnect/core/src/main/resources/resources/FrameworkErrors.xml b/interconnect/core/src/main/resources/resources/FrameworkErrors.xml
new file mode 100644
index 00000000..8a618586
--- /dev/null
+++ b/interconnect/core/src/main/resources/resources/FrameworkErrors.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/InterconnectConstants.java b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/InterconnectConstants.java
index aa1c3ce3..8372d803 100644
--- a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/InterconnectConstants.java
+++ b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/InterconnectConstants.java
@@ -37,10 +37,5 @@ public final class InterconnectConstants {
/** name of the boolean message property that indicates whether the message contains a regular result or an error object */
public static final String MSGPROP_ERROR = "error";
- /** Constant for the system property that holds the AES key for message encryption */
- public static final String PROPERTY_CRYPTO_AESKEY = "interconnect.crypto.aes";
-
- /** Constant for the system property that holds the Signature key for message encryption */
- public static final String PROPERTY_CRYPTO_SIGNATURE = "interconnect.crypto.signature";
}
diff --git a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/ivo/IPageableExtension.java b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/ivo/IPageableExtension.java
new file mode 100644
index 00000000..03b3f676
--- /dev/null
+++ b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/ivo/IPageableExtension.java
@@ -0,0 +1,17 @@
+package de.taimos.dvalin.interconnect.model.ivo;
+
+import java.util.List;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public interface IPageableExtension extends IPageable {
+
+ /**
+ * @return a list of fields to sort by and their direction
+ */
+ List getSortExtension();
+}
diff --git a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/ivo/PageableSort.java b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/ivo/PageableSort.java
new file mode 100644
index 00000000..57c97cde
--- /dev/null
+++ b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/ivo/PageableSort.java
@@ -0,0 +1,36 @@
+package de.taimos.dvalin.interconnect.model.ivo;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class PageableSort {
+
+ private final String field;
+ private final Direction direction;
+
+ /**
+ * @param field to sort by
+ * @param direction to sort by
+ */
+ public PageableSort(String field, Direction direction) {
+ this.field = field;
+ this.direction = direction;
+ }
+
+ /**
+ * @return the field
+ */
+ public String getField() {
+ return this.field;
+ }
+
+ /**
+ * @return the direction
+ */
+ public Direction getDirection() {
+ return this.direction;
+ }
+}
diff --git a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/service/DaemonError.java b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/service/DaemonError.java
index 07083499..de72ccb4 100644
--- a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/service/DaemonError.java
+++ b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/service/DaemonError.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -26,65 +26,66 @@
*/
public class DaemonError extends Exception {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 1L;
- /** Number (never null). */
- private final DaemonErrorNumber number;
+ /**
+ * Number (never null).
+ */
+ private final DaemonErrorNumber number;
+ /**
+ * @param aNumber Number
+ */
+ public DaemonError(final DaemonErrorNumber aNumber) {
+ super(((aNumber != null) ? aNumber.daemon() + " #" + aNumber.get() : ""));
+ if (aNumber == null) {
+ throw new IllegalArgumentException("number was null");
+ }
+ this.number = aNumber;
+ }
- /**
- * @param aNumber Number
- */
- public DaemonError(final DaemonErrorNumber aNumber) {
- super(((aNumber != null) ? aNumber.daemon() + " #" + aNumber.get() : ""));
- if (aNumber == null) {
- throw new IllegalArgumentException("number was null");
- }
- this.number = aNumber;
- }
+ /**
+ * @param aNumber Number
+ * @param message Message
+ */
+ public DaemonError(final DaemonErrorNumber aNumber, final String message) {
+ super(message);
+ if (aNumber == null) {
+ throw new IllegalArgumentException("number was null");
+ }
+ this.number = aNumber;
+ }
- /**
- * @param aNumber Number
- * @param message Message
- */
- public DaemonError(final DaemonErrorNumber aNumber, final String message) {
- super(message);
- if (aNumber == null) {
- throw new IllegalArgumentException("number was null");
- }
- this.number = aNumber;
- }
+ /**
+ * @param aNumber Number
+ * @param cause Cause
+ */
+ public DaemonError(final DaemonErrorNumber aNumber, final Throwable cause) {
+ super((aNumber != null) ? aNumber.daemon() + " #" + aNumber.get() : "", cause);
+ if (aNumber == null) {
+ throw new IllegalArgumentException("number was null");
+ }
+ this.number = aNumber;
+ }
- /**
- * @param aNumber Number
- * @param cause Cause
- */
- public DaemonError(final DaemonErrorNumber aNumber, final Throwable cause) {
- super((aNumber != null) ? aNumber.daemon() + " #" + aNumber.get() : "", cause);
- if (aNumber == null) {
- throw new IllegalArgumentException("number was null");
- }
- this.number = aNumber;
- }
+ /**
+ * @param aNumber Number
+ * @param message Message
+ * @param cause Cause
+ */
+ public DaemonError(final DaemonErrorNumber aNumber, final String message, final Throwable cause) {
+ super(message, cause);
+ if (aNumber == null) {
+ throw new IllegalArgumentException("number was null");
+ }
+ this.number = aNumber;
+ }
- /**
- * @param aNumber Number
- * @param message Message
- * @param cause Cause
- */
- public DaemonError(final DaemonErrorNumber aNumber, final String message, final Throwable cause) {
- super(message, cause);
- if (aNumber == null) {
- throw new IllegalArgumentException("number was null");
- }
- this.number = aNumber;
- }
-
- /**
- * @return Number
- */
- public DaemonErrorNumber getNumber() {
- return this.number;
- }
+ /**
+ * @return Number
+ */
+ public DaemonErrorNumber getNumber() {
+ return this.number;
+ }
}
diff --git a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/service/IDaemon.java b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/service/IDaemon.java
index 3c580215..bf8b1542 100644
--- a/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/service/IDaemon.java
+++ b/interconnect/model/src/main/java/de/taimos/dvalin/interconnect/model/service/IDaemon.java
@@ -28,14 +28,14 @@
*/
public interface IDaemon {
- // marker interface
+ // marker interface
- /**
- * @param req {@link PingIVO}
- * @return {@link PongIVO}
+ /**
+ * @param req {@link PingIVO}
+ * @return {@link PongIVO}
* @throws DaemonError the daemon error
- */
- @DaemonRequestMethod(idempotent = true)
+ */
+ @DaemonRequestMethod(idempotent = true)
PongIVO alive(PingIVO req) throws DaemonError;
}
diff --git a/interconnect/pom.xml b/interconnect/pom.xml
index e7cb92ad..771a097b 100644
--- a/interconnect/pom.xml
+++ b/interconnect/pom.xml
@@ -18,6 +18,7 @@
metamodel
interconnect-maven-plugin
core
- test
+ core-legacy
+ test-legacy
diff --git a/interconnect/test/pom.xml b/interconnect/test-legacy/pom.xml
similarity index 83%
rename from interconnect/test/pom.xml
rename to interconnect/test-legacy/pom.xml
index 691213dc..750509ee 100644
--- a/interconnect/test/pom.xml
+++ b/interconnect/test-legacy/pom.xml
@@ -5,14 +5,14 @@
dvalin-interconnect-parent
1.36-SNAPSHOT
- dvalin-interconnect-test
+ dvalin-interconnect-test-legacy
Dvalin interconnect test library
de.taimos
- dvalin-interconnect-core
+ dvalin-interconnect-core-legacy
${project.version}
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/DaemonMessageSenderMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/DaemonMessageSenderMock.java
similarity index 99%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/DaemonMessageSenderMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/DaemonMessageSenderMock.java
index d1115404..a9983379 100644
--- a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/DaemonMessageSenderMock.java
+++ b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/DaemonMessageSenderMock.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/IMessageMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/IMessageMock.java
similarity index 99%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/IMessageMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/IMessageMock.java
index 17b729ce..63327683 100644
--- a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/IMessageMock.java
+++ b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/message/IMessageMock.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/DaemonRequestResponseMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/DaemonRequestResponseMock.java
similarity index 100%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/DaemonRequestResponseMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/DaemonRequestResponseMock.java
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/IRequestMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/IRequestMock.java
similarity index 99%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/IRequestMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/IRequestMock.java
index cebdfec6..cfca6268 100644
--- a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/IRequestMock.java
+++ b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/requestresponse/IRequestMock.java
@@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/ADaemonTest.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/ADaemonTest.java
similarity index 100%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/ADaemonTest.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/ADaemonTest.java
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/APrototypeHandlerMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/APrototypeHandlerMock.java
similarity index 100%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/APrototypeHandlerMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/APrototypeHandlerMock.java
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/ASingletonHandlerMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/ASingletonHandlerMock.java
similarity index 100%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/ASingletonHandlerMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/ASingletonHandlerMock.java
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/BrokerMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/BrokerMock.java
similarity index 100%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/BrokerMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/BrokerMock.java
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/InterconnectRequestMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/InterconnectRequestMock.java
similarity index 91%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/InterconnectRequestMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/InterconnectRequestMock.java
index 0b0d7dca..f3aac2f6 100644
--- a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/InterconnectRequestMock.java
+++ b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/InterconnectRequestMock.java
@@ -20,24 +20,7 @@
* #L%
*/
-import java.lang.reflect.Array;
-import java.lang.reflect.InvocationTargetException;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.annotation.PostConstruct;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.ListableBeanFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-
import com.google.common.collect.Maps;
-
import de.taimos.daemon.spring.annotations.TestComponent;
import de.taimos.dvalin.interconnect.core.spring.requestresponse.IRequestMock;
import de.taimos.dvalin.interconnect.model.InterconnectContext;
@@ -49,6 +32,20 @@
import de.taimos.dvalin.interconnect.model.service.DaemonScanner;
import de.taimos.dvalin.interconnect.model.service.DaemonScanner.DaemonMethod;
import de.taimos.dvalin.interconnect.model.service.IDaemonHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.annotation.PostConstruct;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
@TestComponent("requestMock")
public class InterconnectRequestMock implements IRequestMock {
@@ -68,13 +65,15 @@ public class InterconnectRequestMock implements IRequestMock {
public void init() {
final String[] prototypeNames = this.beanFactory.getBeanNamesForType(APrototypeHandlerMock.class);
for (final String name : prototypeNames) {
- Class extends APrototypeHandlerMock> type = (Class extends APrototypeHandlerMock>) this.beanFactory.getType(name);
+ Class extends APrototypeHandlerMock> type = (Class extends APrototypeHandlerMock>) this.beanFactory.getType(
+ name);
InterconnectRequestMock.LOGGER.info("Found request mock of type {} with name {}", type, name);
this.registerPrototype(type, name);
}
final String[] singletonNames = this.beanFactory.getBeanNamesForType(ASingletonHandlerMock.class);
for (final String name : singletonNames) {
- Class extends ASingletonHandlerMock> type = (Class extends ASingletonHandlerMock>) this.beanFactory.getType(name);
+ Class extends ASingletonHandlerMock> type = (Class extends ASingletonHandlerMock>) this.beanFactory.getType(
+ name);
InterconnectRequestMock.LOGGER.info("Found request mock of type {} with name {}", type, name);
this.registerSingleton(type, name);
}
@@ -153,9 +152,9 @@ public void receive(UUID uuid, String queue, InterconnectObject request) {
public interface RequestMockHandler {
/**
- * @param response class type
- * @param uuid the uuid
- * @param ico the interconnect object
+ * @param response class type
+ * @param uuid the uuid
+ * @param ico the interconnect object
* @param responseClazz the response class
* @return the response
* @throws DaemonError if deamon error
@@ -164,7 +163,7 @@ public interface RequestMockHandler {
/**
* @param uuid the uuid
- * @param ico the interconnect object
+ * @param ico the interconnect object
*/
void handle(UUID uuid, InterconnectObject ico);
@@ -204,8 +203,10 @@ public R handle(UUID uuid, InterconnectObject ico, Class responseClazz) t
InterconnectObject ivo = daemonMethod.invoke(mockInstance, ico);
if (responseClazz.isArray() && (ivo instanceof InterconnectList)) {
final InterconnectList list = (InterconnectList) ivo;
- final Object obj = Array.newInstance(responseClazz.getComponentType(), list.getElements().size());
- return (R) list.getElements().toArray(DaemonScanner.object2Array(responseClazz.getComponentType(), obj));
+ final Object obj = Array.newInstance(responseClazz.getComponentType(),
+ list.getElements().size());
+ return (R) list.getElements()
+ .toArray(DaemonScanner.object2Array(responseClazz.getComponentType(), obj));
} else if ((ivo instanceof InterconnectList) && List.class.isAssignableFrom(responseClazz)) {
final InterconnectList list = (InterconnectList) ivo;
return (R) list.getElements();
@@ -233,7 +234,8 @@ public void handle(UUID uuid, InterconnectObject ico) {
if (daemonMethod.invoke(mockInstance, ico) == null) {
return;
}
- } catch (IllegalAccessException | IllegalArgumentException | SecurityException | InvocationTargetException e) {
+ } catch (IllegalAccessException | IllegalArgumentException | SecurityException |
+ InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@@ -251,12 +253,8 @@ private IDaemonHandler createMockInstance(Class extends InterconnectObject> iv
}
final IDaemonHandler mockInstance;
if (this.singleton) {
- mockInstance = (ASingletonHandlerMock) this.beanFactory.getBean(this.beanName);
+ mockInstance = (ASingletonHandlerMock) this.beanFactory.getBean(this.beanName);
} else {
- // TODO check Spring startup state to prevent errors from prototype mocks
- // if (SpringMain.isStarting()) {
- // throw new RuntimeException("Protoype mocks can not be used during starting phase!");
- // }
mockInstance = (APrototypeHandlerMock) this.beanFactory.getBean(this.beanName);
}
return mockInstance;
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/MessageSenderMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/MessageSenderMock.java
similarity index 100%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/MessageSenderMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/MessageSenderMock.java
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/PrototypeHandlerMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/PrototypeHandlerMock.java
similarity index 100%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/PrototypeHandlerMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/PrototypeHandlerMock.java
diff --git a/interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/SingletonHandlerMock.java b/interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/SingletonHandlerMock.java
similarity index 100%
rename from interconnect/test/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/SingletonHandlerMock.java
rename to interconnect/test-legacy/src/main/java/de/taimos/dvalin/interconnect/core/spring/test/SingletonHandlerMock.java
diff --git a/interconnect/test-legacy/src/main/resources/.gitkeep b/interconnect/test-legacy/src/main/resources/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/interconnect/test-legacy/src/test/java/.gitkeep b/interconnect/test-legacy/src/test/java/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/interconnect/test-legacy/src/test/resources/.gitkeep b/interconnect/test-legacy/src/test/resources/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/interconnect/test/dvalin-interconnect-test.iml b/interconnect/test/dvalin-interconnect-test.iml
deleted file mode 100644
index 61e2e163..00000000
--- a/interconnect/test/dvalin-interconnect-test.iml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/jms/README.md b/jms/README.md
new file mode 100644
index 00000000..303af1f1
--- /dev/null
+++ b/jms/README.md
@@ -0,0 +1,10 @@
+## jms
+
+### dvalin-jms-core
+Interface IJmsConnector for usage of java messenging system. Use with `dvalin-jms-activemq-classic` or own implementation.
+
+### dvalin-jms--activemq-classic
+ActiveMQ Classic implementation for the Dvalin JMS core.
+
+### dvalin-jms-test
+Mocks to use for testing applications.
\ No newline at end of file
diff --git a/jms/activemq-classic/pom.xml b/jms/activemq-classic/pom.xml
new file mode 100644
index 00000000..1d72dd79
--- /dev/null
+++ b/jms/activemq-classic/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+
+ de.taimos
+ dvalin-parent
+ 1.36-SNAPSHOT
+ ../../pom.xml
+
+
+ dvalin-jms-activemq-classic
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ de.taimos
+ dvalin-jms-core
+ ${project.version}
+ compile
+
+
+
+ de.taimos
+ dvalin-daemon
+ ${project.version}
+
+
+
+
+ org.apache.activemq
+ activemq-pool
+ ${activemq.version}
+
+
+ org.apache.activemq
+ activemq-client
+ ${activemq.version}
+
+
+
+
\ No newline at end of file
diff --git a/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/ActiveMQPooledConnectionFactory.java b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/ActiveMQPooledConnectionFactory.java
new file mode 100644
index 00000000..146bf319
--- /dev/null
+++ b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/ActiveMQPooledConnectionFactory.java
@@ -0,0 +1,41 @@
+package de.taimos.dvalin.jms.activemq;
+
+import org.apache.activemq.pool.PooledConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jms.ConnectionFactory;
+
+/**
+ * Copyright 2022 Cinovo AG
+ *
+ *
+ * @author aeichel
+ */
+public class ActiveMQPooledConnectionFactory extends PooledConnectionFactory {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ActiveMQPooledConnectionFactory.class);
+
+ /**
+ * @param connectionFactory a connection factory
+ * @return initialized connection pool
+ */
+ public ActiveMQPooledConnectionFactory initDefault(ConnectionFactory connectionFactory) {
+ try {
+
+ this.setConnectionFactory(connectionFactory);
+ this.setCreateConnectionOnStartup(true);
+ this.setIdleTimeout(0);
+ this.setMaxConnections(3);
+ this.setMaximumActiveSessionPerConnection(100);
+ this.setTimeBetweenExpirationCheckMillis(30000);
+ this.setBlockIfSessionPoolIsFull(false);
+
+ // start connection pool
+ this.start();
+ } catch (Exception e) {
+ ActiveMQPooledConnectionFactory.LOGGER.error("Failed to setup the message queues", e);
+ }
+ return this;
+ }
+}
diff --git a/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/ActiveMqCryptoService.java b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/ActiveMqCryptoService.java
new file mode 100644
index 00000000..8f842acd
--- /dev/null
+++ b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/ActiveMqCryptoService.java
@@ -0,0 +1,48 @@
+package de.taimos.dvalin.jms.activemq;
+
+import de.taimos.dvalin.jms.crypto.ACryptoService;
+import de.taimos.dvalin.jms.crypto.JmsMessageCryptoUtil;
+import de.taimos.dvalin.jms.exceptions.MessageCryptoException;
+import org.apache.activemq.command.ActiveMQTextMessage;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.TextMessage;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class ActiveMqCryptoService extends ACryptoService {
+
+ @Override
+ public Message decryptMessage(Message msg) throws MessageCryptoException {
+ if (!(msg instanceof TextMessage)) {
+ return msg;
+ }
+ TextMessage txt = (TextMessage) msg;
+ try {
+ if (!txt.propertyExists(JmsMessageCryptoUtil.SIGNATURE_HEADER)) {
+ throw new MessageCryptoException();
+ }
+ final String signature = txt.getStringProperty(JmsMessageCryptoUtil.SIGNATURE_HEADER);
+ final boolean validate = JmsMessageCryptoUtil.validate(txt.getText(), signature);
+ if (!validate) {
+ throw new MessageCryptoException();
+ }
+
+ if (txt instanceof ActiveMQTextMessage) {
+ final ActiveMQTextMessage t = (ActiveMQTextMessage) txt;
+ t.setReadOnlyBody(false);
+ }
+
+ final String decryptedText = JmsMessageCryptoUtil.decrypt(txt.getText());
+ txt.setText(decryptedText);
+ } catch (final JMSException e) {
+ throw new MessageCryptoException(e);
+ }
+ return txt;
+ }
+}
diff --git a/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/ActiveMqDestinationService.java b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/ActiveMqDestinationService.java
new file mode 100644
index 00000000..ee7af37f
--- /dev/null
+++ b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/ActiveMqDestinationService.java
@@ -0,0 +1,44 @@
+package de.taimos.dvalin.jms.activemq;
+
+import de.taimos.dvalin.jms.IDestinationService;
+import de.taimos.dvalin.jms.model.JmsTarget;
+import org.apache.activemq.command.ActiveMQQueue;
+import org.apache.activemq.command.ActiveMQTempQueue;
+import org.apache.activemq.command.ActiveMQTempTopic;
+import org.apache.activemq.command.ActiveMQTopic;
+
+import javax.annotation.Nonnull;
+import javax.jms.Destination;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class ActiveMqDestinationService implements IDestinationService {
+
+ /**
+ * Default constructor
+ */
+ public ActiveMqDestinationService() {
+ }
+
+ @Override
+ public Destination createDestination(@Nonnull JmsTarget type, @Nonnull String name) {
+ switch (type) {
+ case QUEUE:
+ return new ActiveMQQueue(name);
+ case TEMPORARY_QUEUE:
+ return new ActiveMQTempQueue(name);
+ case TOPIC:
+ return new ActiveMQTopic(name);
+ case TEMPORARY_TOPIC:
+ return new ActiveMQTempTopic(name);
+ case DESTINATION:
+ case RECEPTION_CONTEXT:
+ default:
+ throw new UnsupportedOperationException("Not supported for ActiveMQ Classic");
+ }
+ }
+}
diff --git a/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/DvalinActiveMqConnectionFactory.java b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/DvalinActiveMqConnectionFactory.java
new file mode 100644
index 00000000..ec7ed747
--- /dev/null
+++ b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/DvalinActiveMqConnectionFactory.java
@@ -0,0 +1,102 @@
+package de.taimos.dvalin.jms.activemq;
+
+import de.taimos.dvalin.jms.DvalinConnectionFactory;
+import org.apache.activemq.ActiveMQConnectionFactory;
+import org.apache.activemq.ClientInternalExceptionListener;
+import org.apache.activemq.transport.TransportListener;
+import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;
+
+import javax.jms.ExceptionListener;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+@SuppressWarnings("unused")
+public class DvalinActiveMqConnectionFactory extends DvalinConnectionFactory {
+
+ /**
+ * Construct a {@link DvalinConnectionFactory} for ActiveMQ Classic, uses {@link DvalinConnectionFactory#getBrokerURL()} default broker url
+ */
+ public DvalinActiveMqConnectionFactory() {
+ this(DvalinConnectionFactory.getBrokerURL());
+ }
+
+ /**
+ * Construct a {@link DvalinConnectionFactory} for ActiveMQ Classic, uses the supplied broker url.
+ *
+ * @param brokerURL url for the broker
+ */
+ public DvalinActiveMqConnectionFactory(String brokerURL) {
+ super(new ActiveMQConnectionFactory(brokerURL));
+ }
+
+ /**
+ * Construct a {@link DvalinConnectionFactory} for ActiveMQ Classic, uses the supplied broker url.
+ *
+ * @param brokerURL url for the broker
+ * @param userName used by the broker
+ * @param password used by the broker
+ */
+ public DvalinActiveMqConnectionFactory(String brokerURL, String userName, String password) {
+ super(new ActiveMQConnectionFactory(brokerURL), userName, password);
+ }
+
+ /**
+ * @param listener exception listener
+ */
+ @Override
+ public void setExceptionListener(ExceptionListener listener) {
+ if (this.innerAdapter instanceof ActiveMQConnectionFactory) {
+ ((ActiveMQConnectionFactory) this.innerAdapter).setExceptionListener(listener);
+ } else if (this.innerAdapter instanceof UserCredentialsConnectionFactoryAdapter) {
+ if (this.innerFactory instanceof ActiveMQConnectionFactory) {
+ ((ActiveMQConnectionFactory) this.innerFactory).setExceptionListener(listener);
+ }
+ }
+ }
+
+ /**
+ * @param trustAllPackages trust all packages, default false
+ */
+ @Override
+ public void setTrustAllPackages(boolean trustAllPackages) {
+ if (this.innerAdapter instanceof ActiveMQConnectionFactory) {
+ ((ActiveMQConnectionFactory) this.innerAdapter).setTrustAllPackages(trustAllPackages);
+ } else if (this.innerAdapter instanceof UserCredentialsConnectionFactoryAdapter) {
+ if (this.innerFactory instanceof ActiveMQConnectionFactory) {
+ ((ActiveMQConnectionFactory) this.innerFactory).setTrustAllPackages(trustAllPackages);
+ }
+ }
+
+ }
+
+ /**
+ * @param listener client internal exception listener
+ */
+ public void setClientInternalExceptionListener(ClientInternalExceptionListener listener) {
+ if (this.innerAdapter instanceof ActiveMQConnectionFactory) {
+ ((ActiveMQConnectionFactory) this.innerAdapter).setClientInternalExceptionListener(listener);
+ } else if (this.innerAdapter instanceof UserCredentialsConnectionFactoryAdapter) {
+ if (this.innerFactory instanceof ActiveMQConnectionFactory) {
+ ((ActiveMQConnectionFactory) this.innerFactory).setClientInternalExceptionListener(listener);
+ }
+ }
+
+ }
+
+ /**
+ * @param listener transport exception listener
+ */
+ public void setTransportListener(TransportListener listener) {
+ if (this.innerAdapter instanceof ActiveMQConnectionFactory) {
+ ((ActiveMQConnectionFactory) this.innerAdapter).setTransportListener(listener);
+ } else if (this.innerAdapter instanceof UserCredentialsConnectionFactoryAdapter) {
+ if (this.innerFactory instanceof ActiveMQConnectionFactory) {
+ ((ActiveMQConnectionFactory) this.innerFactory).setTransportListener(listener);
+ }
+ }
+ }
+}
diff --git a/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/config/JMSConfig.java b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/config/JMSConfig.java
new file mode 100644
index 00000000..893ea25c
--- /dev/null
+++ b/jms/activemq-classic/src/main/java/de/taimos/dvalin/jms/activemq/config/JMSConfig.java
@@ -0,0 +1,100 @@
+package de.taimos.dvalin.jms.activemq.config;
+
+/*-
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 - 2017 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.jms.DvalinConnectionFactory;
+import de.taimos.dvalin.jms.IDestinationService;
+import de.taimos.dvalin.jms.IJmsConnector;
+import de.taimos.dvalin.jms.JmsConnector;
+import de.taimos.dvalin.jms.activemq.ActiveMQPooledConnectionFactory;
+import de.taimos.dvalin.jms.activemq.ActiveMqCryptoService;
+import de.taimos.dvalin.jms.activemq.ActiveMqDestinationService;
+import de.taimos.dvalin.jms.activemq.DvalinActiveMqConnectionFactory;
+import de.taimos.dvalin.jms.crypto.ICryptoService;
+import org.apache.activemq.jms.pool.PooledConnectionFactory;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+
+/**
+ * Default configuration for dvalin-jms with ActiveMQ Classic.
+ *
+ * @author fzwirn
+ */
+@Configuration
+@Profile(de.taimos.daemon.spring.Configuration.PROFILES_PRODUCTION)
+public class JMSConfig {
+
+ @Value("${interconnect.jms.broker}")
+ private String brokerUrl;
+
+ @Value("${interconnect.jms.userName:#{null}}")
+ private String userName;
+
+ @Value("${interconnect.jms.password:}")
+ private String password;
+
+ /**
+ * @return a Dvalin JMS connection factory for ActiveMQ Classic
+ */
+ @Bean(name = "DvalinConnectionFactory", destroyMethod = "stop")
+ public DvalinConnectionFactory jmsConnectionFactory() {
+ return new DvalinActiveMqConnectionFactory(this.brokerUrl, this.userName, this.password);
+ }
+
+ /**
+ * @param jmsConnectionFactory the JMS connection factory to be used
+ * @return a pooled connection factory for ActiveMQ Classic
+ */
+ @Bean(name = "DvalinPooledConnectionFactory", destroyMethod = "stop")
+ public PooledConnectionFactory jmsPooledConnectionFactory(DvalinConnectionFactory jmsConnectionFactory) {
+ return new ActiveMQPooledConnectionFactory().initDefault(jmsConnectionFactory);
+ }
+
+ /**
+ * @param jmsConnectionFactory the JMS connection factory to be used
+ * @param cryptoService the crypto service
+ * @return an instance of {@link IJmsConnector} that uses the {@code jmsConnectionFactory} and the {@code cryptoService}
+ */
+ @Bean
+ public IJmsConnector jmsConnector(@Qualifier("DvalinPooledConnectionFactory") PooledConnectionFactory jmsConnectionFactory, ICryptoService cryptoService) {
+ return new JmsConnector(jmsConnectionFactory, cryptoService);
+ }
+
+ /**
+ * @return a ActiveMQ Classic implementation of {@link ICryptoService}
+ */
+ @Bean
+ public ICryptoService cryptoService() {
+ return new ActiveMqCryptoService();
+ }
+
+ /**
+ * @return a ActiveMQ Classic implementation of {@link IDestinationService}
+ */
+ @Bean
+ public IDestinationService serviceDestination() {
+ return new ActiveMqDestinationService();
+ }
+}
diff --git a/jms/core/pom.xml b/jms/core/pom.xml
new file mode 100644
index 00000000..397029df
--- /dev/null
+++ b/jms/core/pom.xml
@@ -0,0 +1,43 @@
+
+
+ 4.0.0
+
+ de.taimos
+ dvalin-parent
+ 1.36-SNAPSHOT
+
+
+ dvalin-jms-core
+
+
+
+ javax.jms
+ javax.jms-api
+ 2.0.1
+
+
+
+ commons-codec
+ commons-codec
+
+
+
+
+
+ org.springframework
+ spring-jms
+ ${org.springframework.version}
+
+
+
+ org.springframework
+ spring-context
+ ${org.springframework.version}
+
+
+
+
\ No newline at end of file
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/DvalinConnectionFactory.java b/jms/core/src/main/java/de/taimos/dvalin/jms/DvalinConnectionFactory.java
new file mode 100644
index 00000000..50aee046
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/DvalinConnectionFactory.java
@@ -0,0 +1,144 @@
+package de.taimos.dvalin.jms;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;
+
+import javax.annotation.Nonnull;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSContext;
+import javax.jms.JMSException;
+
+/**
+ * Copyright 2022 Cinovo AG
+ *
+ *
+ * @author aeichel, fzwirn
+ */
+@SuppressWarnings("unused")
+public class DvalinConnectionFactory implements ConnectionFactory {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DvalinConnectionFactory.class);
+
+ public static final String SYSPROP_USERNAME = "interconnect.jms.userName";
+ public static final String SYSPROP_PASSWORD = "interconnect.jms.password";
+ /**
+ * name of the system property that contains the interconnect broker URL
+ */
+ public static final String SYSPROP_IBROKERURL = "interconnect.jms.broker";
+
+ private static final String FALLBACK_BROKER_URL = "tcp://localhost:61616";
+
+ protected ConnectionFactory innerFactory;
+ protected ConnectionFactory innerAdapter;
+
+ private final String userName;
+ private final String password;
+
+ /**
+ * Uses {@link DvalinConnectionFactory#SYSPROP_IBROKERURL} as a broker url, or a default broker {@link DvalinConnectionFactory#FALLBACK_BROKER_URL}.
+ *
+ * @return a broker url
+ */
+ public static String getBrokerURL() {
+ String brokerURL = System.getProperty(DvalinConnectionFactory.SYSPROP_IBROKERURL);
+ if (brokerURL == null) {
+ DvalinConnectionFactory.LOGGER.warn("No {} configured, using default {}",
+ DvalinConnectionFactory.SYSPROP_IBROKERURL, DvalinConnectionFactory.FALLBACK_BROKER_URL);
+ brokerURL = DvalinConnectionFactory.FALLBACK_BROKER_URL;
+ }
+ return brokerURL;
+ }
+
+ /**
+ * @param innerFactory the connection factory used by this wrapper.
+ */
+ public DvalinConnectionFactory(@Nonnull ConnectionFactory innerFactory) {
+ this(innerFactory, System.getProperty(DvalinConnectionFactory.SYSPROP_USERNAME),
+ System.getProperty(DvalinConnectionFactory.SYSPROP_PASSWORD));
+ }
+
+ /**
+ * @param innerFactory the connection factory used by this wrapper.
+ * @param userName the username
+ * @param password the password
+ */
+ public DvalinConnectionFactory(@Nonnull ConnectionFactory innerFactory, String userName, String password) {
+ this.userName = userName;
+ this.password = password;
+ this.init(innerFactory);
+ }
+
+ protected void init(@Nonnull ConnectionFactory innerFactory) {
+ this.innerFactory = innerFactory;
+ if (this.userName == null || this.userName.isEmpty()) {
+ this.innerAdapter = this.innerFactory;
+ return;
+ }
+ UserCredentialsConnectionFactoryAdapter credentialConnectionFactory = new UserCredentialsConnectionFactoryAdapter();
+ credentialConnectionFactory.setTargetConnectionFactory(this.innerFactory);
+ credentialConnectionFactory.setUsername(this.userName);
+ credentialConnectionFactory.setPassword(this.password);
+ this.innerAdapter = credentialConnectionFactory;
+ }
+
+ /**
+ * @param listener exception listener
+ */
+ public void setExceptionListener(ExceptionListener listener) {
+ // Implement if needed
+ }
+
+ /**
+ * @param trustAllPackages trust all packages, default false
+ */
+ public void setTrustAllPackages(boolean trustAllPackages) {
+ // Implement if needed
+ }
+
+ /**
+ * Start the connection factory
+ */
+ public void start() {
+ // Implement if needed
+ }
+
+ /**
+ * Stop the connection factory
+ */
+ public void stop() {
+ // Implement if needed
+ }
+
+ @Override
+ public Connection createConnection() throws JMSException {
+ return this.innerAdapter.createConnection();
+ }
+
+ @Override
+ public Connection createConnection(String userName, String password) throws JMSException {
+ return this.innerAdapter.createConnection(userName, password);
+ }
+
+ @Override
+ public JMSContext createContext() {
+ return this.innerAdapter.createContext();
+ }
+
+ @Override
+ public JMSContext createContext(String userName, String password) {
+ return this.innerAdapter.createContext(userName, password);
+ }
+
+ @Override
+ public JMSContext createContext(String userName, String password, int sessionMode) {
+ return this.innerAdapter.createContext(userName, password, sessionMode);
+ }
+
+ @Override
+ public JMSContext createContext(int sessionMode) {
+ return this.innerAdapter.createContext(sessionMode);
+ }
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/IDestinationService.java b/jms/core/src/main/java/de/taimos/dvalin/jms/IDestinationService.java
new file mode 100644
index 00000000..267932ac
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/IDestinationService.java
@@ -0,0 +1,23 @@
+package de.taimos.dvalin.jms;
+
+import de.taimos.dvalin.jms.model.JmsTarget;
+
+import javax.annotation.Nonnull;
+import javax.jms.Destination;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public interface IDestinationService {
+
+ /**
+ * @param type of the destination
+ * @param name of the destination
+ * @return a JMS destination
+ * @throws UnsupportedOperationException in case the target can not be mapped by the implementation
+ */
+ Destination createDestination(@Nonnull JmsTarget type, @Nonnull String name) throws UnsupportedOperationException;
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/IJmsConnector.java b/jms/core/src/main/java/de/taimos/dvalin/jms/IJmsConnector.java
new file mode 100644
index 00000000..9e44b742
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/IJmsConnector.java
@@ -0,0 +1,93 @@
+package de.taimos.dvalin.jms;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.jms.exceptions.InfrastructureException;
+import de.taimos.dvalin.jms.exceptions.SerializationException;
+import de.taimos.dvalin.jms.model.JmsContext;
+import de.taimos.dvalin.jms.model.JmsResponseContext;
+
+import javax.annotation.Nonnull;
+import javax.jms.Message;
+import java.util.List;
+
+/**
+ * Connector to connect to JMS providers.
+ *
+ * @author Thorsten Hoeger
+ * @author fzwirn
+ */
+@SuppressWarnings("unused")
+public interface IJmsConnector {
+ /**
+ * name of the system property that contains the interconnect update topic name
+ */
+ String SYSPROP_UPDATE_TOPIC = "interconnect.jms.updatetopic";
+
+ /**
+ * name of the system property that contains the interconnect virtual topic prefix
+ */
+ String SYSPROP_VIRTUAL_TOPIC_PREFIX = "interconnect.jms.virtualtopic.prefix";
+
+ /**
+ * the default request timeout (in Milliseconds)
+ */
+ long REQUEST_TIMEOUT = 10000;
+
+ /**
+ * the message priority to use when sending a message over the message queue
+ */
+ int MSGPRIORITY = 5;
+
+
+ /**
+ * @param context holds all necessary information for the send operation
+ * @throws InfrastructureException in case of general errors
+ * @throws SerializationException in case of problems with encryption
+ */
+ void send(@Nonnull JmsContext context) throws InfrastructureException, SerializationException;
+
+ /**
+ * @param context holds all necessary information for the request operation
+ * @return response of the request
+ * @throws InfrastructureException in case of general errors
+ * @throws SerializationException in case of problems with encryption
+ */
+ JmsResponseContext extends Message> request(@Nonnull JmsContext context) throws InfrastructureException, SerializationException;
+
+ /**
+ * @param context holds all necessary information for the reception operation
+ * @return response received
+ * @throws InfrastructureException in case of general errors
+ * @throws SerializationException in case of problems with encryption
+ */
+ JmsResponseContext extends Message> receive(@Nonnull JmsContext context) throws InfrastructureException, SerializationException;
+
+ /**
+ * @param context holds all necessary information for the request operation
+ * @param maxSize maximum number of messages to wait for.
+ * @return List of response {@link Message}
+ * @throws InfrastructureException in case of general errors
+ * @throws SerializationException in case of problems with encryption
+ */
+ List receiveBulkFromDestination(JmsContext context, int maxSize) throws InfrastructureException, SerializationException;
+
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/JmsConnector.java b/jms/core/src/main/java/de/taimos/dvalin/jms/JmsConnector.java
new file mode 100644
index 00000000..9902f1e3
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/JmsConnector.java
@@ -0,0 +1,226 @@
+package de.taimos.dvalin.jms;
+
+import de.taimos.dvalin.jms.crypto.ICryptoService;
+import de.taimos.dvalin.jms.exceptions.CommunicationFailureException;
+import de.taimos.dvalin.jms.exceptions.CommunicationFailureException.CommunicationError;
+import de.taimos.dvalin.jms.exceptions.CreationException;
+import de.taimos.dvalin.jms.exceptions.CreationException.Source;
+import de.taimos.dvalin.jms.exceptions.InfrastructureException;
+import de.taimos.dvalin.jms.exceptions.SerializationException;
+import de.taimos.dvalin.jms.exceptions.TimeoutException;
+import de.taimos.dvalin.jms.model.JmsContext;
+import de.taimos.dvalin.jms.model.JmsResponseContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TemporaryQueue;
+import javax.jms.TextMessage;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class JmsConnector implements IJmsConnector {
+
+ private final ConnectionFactory connectionFactory;
+ private final ICryptoService cryptoService;
+
+ protected static final Logger logger = LoggerFactory.getLogger(JmsConnector.class);
+
+ /**
+ * @param connectionFactory to use with this connector
+ * @param cryptoService to use with this connector
+ */
+ public JmsConnector(ConnectionFactory connectionFactory, ICryptoService cryptoService) {
+ this.connectionFactory = connectionFactory;
+ this.cryptoService = cryptoService;
+ }
+
+ @Override
+ public void send(@Nonnull JmsContext context) throws SerializationException, InfrastructureException {
+ try (Connection connection = this.connectionFactory.createConnection()) {
+ try (Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) {
+ final Destination destination = JmsConnector.createDestination(session, context);
+ Message txt = this.createTextMessageForDestination(session, context, null);
+ JmsConnector.sendMessage(session, destination, txt,
+ context.getTimeToLive(), context.getPriority());
+ } catch (final JMSException e) {
+ throw new CreationException(Source.SESSION, e);
+ }
+ } catch (JMSException e) {
+ throw new CreationException(Source.CONNECTION, e);
+ }
+ }
+
+ @Override
+ public JmsResponseContext extends Message> receive(@Nonnull JmsContext context) throws InfrastructureException, SerializationException {
+ try (Connection connection = this.connectionFactory.createConnection()) {
+ try (Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) {
+ try (MessageConsumer consumer = session.createConsumer(JmsConnector.createDestination(session, context),
+ context.getSelector())) {
+ connection.start();
+ Message message = this.syncReceiveSingleMessage(consumer, context.getReceiveTimeout(),
+ context.isSecure());
+ return new JmsResponseContext<>(message);
+ } catch (final JMSException e) {
+ throw new CreationException(Source.CONSUMER, e);
+ }
+ } catch (final JMSException e) {
+ throw new CreationException(Source.SESSION, e);
+ }
+ } catch (JMSException e) {
+ throw new CreationException(Source.CONNECTION, e);
+ }
+ }
+
+ @Override
+ public JmsResponseContext extends Message> request(@Nonnull JmsContext context) throws SerializationException, InfrastructureException {
+ try (Connection connection = this.connectionFactory.createConnection()) {
+ try (Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) {
+ try {
+ final TemporaryQueue temporaryQueue = session.createTemporaryQueue();
+ final Queue requestQueue = session.createQueue(context.getDestinationName());
+ final Message txt = this.createTextMessageForDestination(session, context, temporaryQueue);
+
+ try (MessageConsumer consumer = session.createConsumer(temporaryQueue, context.getSelector())) {
+ connection.start();
+ JmsConnector.sendMessage(session, requestQueue, txt,
+ context.getTimeToLive(), context.getPriority());
+ Message response = this.syncReceiveSingleMessage(consumer, context.getReceiveTimeout(),
+ context.isSecure());
+ return new JmsResponseContext<>(response);
+ } catch (final JMSException e) {
+ throw new CreationException(Source.CONSUMER);
+ }
+ } catch (final JMSException e) {
+ throw new CreationException(Source.DESTINATION, e);
+ }
+ } catch (final JMSException e) {
+ throw new CreationException(Source.SESSION, e);
+ }
+ } catch (JMSException e) {
+ throw new CreationException(Source.CONNECTION, e);
+ }
+ }
+
+ private static void sendMessage(Session session, Destination destination, Message txt, long timeToLive, int priority) throws InfrastructureException {
+ try (MessageProducer producer = session.createProducer(destination)) {
+ try {
+ producer.send(destination, txt, DeliveryMode.PERSISTENT, priority, timeToLive);
+ } catch (JMSException e) {
+ throw new CommunicationFailureException(CommunicationError.SEND, e);
+ }
+ } catch (final JMSException e) {
+ throw new CreationException(Source.PRODUCER, e);
+ }
+ }
+
+ @Override
+ public List receiveBulkFromDestination(JmsContext context, final int maxMessages) throws InfrastructureException, SerializationException {
+ try (Connection connection = this.connectionFactory.createConnection()) {
+ try (Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) {
+ Destination destination = JmsConnector.createDestination(session, context);
+ List messages = new ArrayList<>();
+ try (MessageConsumer consumer = session.createConsumer(destination, context.getSelector())) {
+ connection.start();
+ while (messages.size() < maxMessages) {
+ Message message = this.syncReceiveSingleMessage(consumer, context.getReceiveTimeout(),
+ context.isSecure());
+ messages.add(message);
+ }
+ } catch (final JMSException e) {
+ throw new CreationException(Source.CONSUMER, e);
+ }
+ return messages;
+ } catch (final JMSException e) {
+ throw new CreationException(Source.SESSION, e);
+ }
+ } catch (JMSException e) {
+ throw new CreationException(Source.CONNECTION, e);
+ }
+ }
+
+ private static Destination createDestination(Session session, JmsContext context) throws CreationException {
+ try {
+ switch (context.getTarget()) {
+ case DESTINATION:
+ return context.getDestination();
+ case QUEUE:
+ return session.createQueue(context.getDestinationName());
+ case TOPIC:
+ return session.createTopic(context.getDestinationName());
+ default:
+ throw new CreationException(Source.DESTINATION);
+ }
+ } catch (JMSException e) {
+ throw new CreationException(Source.DESTINATION);
+ }
+ }
+
+
+ private Message syncReceiveSingleMessage(MessageConsumer consumer, long timeout, boolean secure) throws CommunicationFailureException, TimeoutException, SerializationException {
+ try {
+ final Message response = consumer.receive(timeout); // Wait for response.
+ if (response == null) {
+ throw new TimeoutException(timeout);
+ }
+ if (response instanceof TextMessage) {
+ TextMessage txtRes = (TextMessage) response;
+ if (secure) {
+ txtRes = (TextMessage) this.cryptoService.decryptMessage(txtRes);
+ }
+ return txtRes;
+ }
+ return response;
+ } catch (final JMSException e) {
+ throw new CommunicationFailureException(CommunicationError.RECEIVE, e);
+ }
+ }
+
+
+ private Message createTextMessageForDestination(Session session, JmsContext sendContext, Destination replyToDestination) throws SerializationException, InfrastructureException {
+ try {
+ Message txt;
+ if (sendContext.getBody() instanceof String) {
+ txt = session.createTextMessage((String) sendContext.getBody());
+ } else {
+ txt = session.createObjectMessage(sendContext.getBody());
+ }
+ if (replyToDestination != null) {
+ txt.setJMSReplyTo(replyToDestination);
+ }
+ if (sendContext.getCorrelationId() != null) {
+ txt.setJMSCorrelationID(sendContext.getCorrelationId());
+ }
+ if (sendContext.getHeaders() != null) {
+ final Set> entrySet = sendContext.getHeaders().entrySet();
+ for (final Entry entry : entrySet) {
+ txt.setObjectProperty(entry.getKey(), entry.getValue());
+ }
+ }
+ if (sendContext.isSecure()) {
+ txt = this.cryptoService.secureMessage(txt);
+ }
+ return txt;
+ } catch (final JMSException e) {
+ throw new CreationException(Source.FAILED_TO_CREATE_MESSAGE, e);
+ }
+ }
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/crypto/ACryptoService.java b/jms/core/src/main/java/de/taimos/dvalin/jms/crypto/ACryptoService.java
new file mode 100644
index 00000000..0138a7ac
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/crypto/ACryptoService.java
@@ -0,0 +1,62 @@
+package de.taimos.dvalin.jms.crypto;
+
+import de.taimos.dvalin.jms.exceptions.MessageCryptoException;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.TextMessage;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public abstract class ACryptoService implements ICryptoService {
+
+
+ @Override
+ public boolean isMessageSecure(final Message txt) throws MessageCryptoException {
+ try {
+ return txt.propertyExists(JmsMessageCryptoUtil.SIGNATURE_HEADER);
+ } catch (JMSException e) {
+ throw new MessageCryptoException(e);
+ }
+ }
+
+ @Override
+ public Message secureMessage(final Message msg) throws JMSException, MessageCryptoException {
+ if (!(msg instanceof TextMessage)) {
+ return msg;
+ }
+ TextMessage txt = (TextMessage) msg;
+ final String cryptedText = JmsMessageCryptoUtil.crypt(txt.getText());
+ txt.setText(cryptedText);
+ txt.setStringProperty(JmsMessageCryptoUtil.SIGNATURE_HEADER, JmsMessageCryptoUtil.sign(cryptedText));
+ return txt;
+ }
+
+ @Override
+ public Message decryptMessage(Message msg) throws MessageCryptoException {
+ if (!(msg instanceof TextMessage)) {
+ return msg;
+ }
+ TextMessage txt = (TextMessage) msg;
+ try {
+ if (!txt.propertyExists(JmsMessageCryptoUtil.SIGNATURE_HEADER)) {
+ throw new MessageCryptoException();
+ }
+ final String signature = txt.getStringProperty(JmsMessageCryptoUtil.SIGNATURE_HEADER);
+ final boolean validate = JmsMessageCryptoUtil.validate(txt.getText(), signature);
+ if (!validate) {
+ throw new MessageCryptoException();
+ }
+
+ final String decryptedText = JmsMessageCryptoUtil.decrypt(txt.getText());
+ txt.setText(decryptedText);
+ } catch (final JMSException e) {
+ throw new MessageCryptoException(e);
+ }
+ return txt;
+ }
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/crypto/ICryptoService.java b/jms/core/src/main/java/de/taimos/dvalin/jms/crypto/ICryptoService.java
new file mode 100644
index 00000000..0521ab26
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/crypto/ICryptoService.java
@@ -0,0 +1,37 @@
+package de.taimos.dvalin.jms.crypto;
+
+import de.taimos.dvalin.jms.exceptions.MessageCryptoException;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public interface ICryptoService {
+
+ /**
+ * @param txt the message to encrypt
+ * @return if message is secure
+ * @throws MessageCryptoException on crypto errors
+ */
+ boolean isMessageSecure(final Message txt) throws MessageCryptoException;
+
+ /**
+ * @param txt the message to encrypt
+ * @return the decrypted text message
+ * @throws MessageCryptoException on crypto errors
+ */
+ Message decryptMessage(final Message txt) throws MessageCryptoException;
+
+ /**
+ * @param txt the message to encrypt
+ * @return the secured text message
+ * @throws JMSException on JMS errors
+ * @throws MessageCryptoException on crypto errors
+ */
+ Message secureMessage(final Message txt) throws JMSException, MessageCryptoException;
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/crypto/JmsMessageCryptoUtil.java b/jms/core/src/main/java/de/taimos/dvalin/jms/crypto/JmsMessageCryptoUtil.java
new file mode 100644
index 00000000..7a941c25
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/crypto/JmsMessageCryptoUtil.java
@@ -0,0 +1,213 @@
+package de.taimos.dvalin.jms.crypto;
+
+/*
+ * #%L
+ * Dvalin interconnect transfer data model
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import de.taimos.dvalin.jms.exceptions.MessageCryptoException;
+import org.apache.commons.codec.binary.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Scanner;
+
+/**
+ * Utility class for encryption and decryption of JMS Messages.
+ *
+ * @author thoeger
+ */
+public final class JmsMessageCryptoUtil {
+
+ private static final Logger logger = LoggerFactory.getLogger(JmsMessageCryptoUtil.class);
+
+ /**
+ * Constant for the system property that holds the AES key for message encryption
+ */
+ public static final String PROPERTY_CRYPTO_AESKEY = "interconnect.crypto.aes";
+
+ /**
+ * Constant for the system property that holds the Signature key for message encryption
+ */
+ public static final String PROPERTY_CRYPTO_SIGNATURE = "interconnect.crypto.signature";
+
+ private JmsMessageCryptoUtil() {
+ // Utility class with private constructor
+ }
+
+
+ /**
+ * The name of the Signature Header
+ */
+ public static final String SIGNATURE_HEADER = "Signature";
+
+ // DO NEVER EVER CHANGE THIS; MESSAGES ARE NOT RECOVERABLE AFTER CHANGE
+ private static final String AES_KEY = System.getProperty(JmsMessageCryptoUtil.PROPERTY_CRYPTO_AESKEY);
+ private static final String SIGNATURE = System.getProperty(JmsMessageCryptoUtil.PROPERTY_CRYPTO_SIGNATURE);
+
+
+ /**
+ * @param data the data to encrypt
+ * @return the encrypted BASE64 data
+ * @throws MessageCryptoException on encryption error
+ */
+ public static String crypt(final String data) throws MessageCryptoException {
+ if (data == null) {
+ return null;
+ }
+ try {
+ SecureRandom secureRandom = new SecureRandom();
+ byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
+ secureRandom.nextBytes(iv);
+ GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
+ final Cipher cipher = JmsMessageCryptoUtil.getCipher(Cipher.ENCRYPT_MODE, parameterSpec);
+
+ final byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
+ ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + encrypted.length);
+ byteBuffer.put(iv);
+ byteBuffer.put(encrypted);
+ byte[] cipherMessage = byteBuffer.array();
+ return Base64.encodeBase64String(cipherMessage);
+ } catch (final Exception e) {
+ throw new MessageCryptoException("Encryption of data failed!", e);
+ }
+ }
+
+ /**
+ * @param data the BASE 64 data
+ * @return the decrypted data
+ * @throws MessageCryptoException on decryption error
+ */
+ public static String decrypt(final String data) throws MessageCryptoException {
+ if (data == null) {
+ return null;
+ }
+ try {
+ byte[] cipherMessage = Base64.decodeBase64(data);
+ AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, cipherMessage, 0, 12);
+ final Cipher cipher = JmsMessageCryptoUtil.getCipher(Cipher.DECRYPT_MODE, gcmIv);
+ return new String(cipher.doFinal(cipherMessage, 12, cipherMessage.length - 12), StandardCharsets.UTF_8);
+ } catch (final Exception e) {
+ throw new MessageCryptoException("Decryption of data failed!", e);
+ }
+ }
+
+ private static Cipher getCipher(int mode, AlgorithmParameterSpec gcmIv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+ final SecretKeySpec skeySpec = new SecretKeySpec(Base64.decodeBase64(JmsMessageCryptoUtil.AES_KEY), "AES");
+ final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(mode, skeySpec, gcmIv);
+ return cipher;
+ }
+
+ /**
+ * @param msg the message to sign
+ * @return the signature hash
+ * @throws MessageCryptoException on sign error
+ */
+ public static String sign(final String msg) throws MessageCryptoException {
+ try {
+ final String toEnc = msg + JmsMessageCryptoUtil.SIGNATURE;
+ final MessageDigest mdEnc = MessageDigest.getInstance("MD5");
+ mdEnc.update(toEnc.getBytes(StandardCharsets.UTF_8), 0, toEnc.length());
+ return new BigInteger(1, mdEnc.digest()).toString(16);
+ } catch (final Exception e) {
+ throw new MessageCryptoException("Creating signature failed", e);
+ }
+ }
+
+ /**
+ * @param msg the message to validate
+ * @param signature the signature hash to check
+ * @return validation result
+ * @throws MessageCryptoException on sign error
+ */
+ public static boolean validate(final String msg, final String signature) throws MessageCryptoException {
+ if ((signature == null) || signature.isEmpty()) {
+ return false;
+ }
+ final String calcSig = JmsMessageCryptoUtil.sign(msg);
+ return calcSig.equals(signature);
+ }
+
+ // ##################################################################
+ // Helper methods to generate keys and (de/en)crypt data
+ // ##################################################################
+
+ /**
+ * start this to generate an AES key or (de/en)crypt data
+ *
+ * @param args the CLI arguments
+ */
+ public static void main(String[] args) {
+ try {
+ System.out.println("Select (k=generate key; c=crypt; d=decrypt):");
+ System.out.println();
+ Scanner scan = new Scanner(System.in, "UTF-8");
+ if (!scan.hasNextLine()) {
+ return;
+ }
+ switch (scan.nextLine()) {
+ case "k":
+ JmsMessageCryptoUtil.generateKey();
+ break;
+ case "c":
+ System.out.print("Input data: ");
+ final String data = scan.nextLine();
+ System.out.println(JmsMessageCryptoUtil.crypt(data));
+ break;
+ case "d":
+ System.out.print("Input data: ");
+ final String ddata = scan.nextLine();
+ System.out.println(JmsMessageCryptoUtil.decrypt(ddata));
+ break;
+ default:
+ break;
+ }
+ } catch (final Exception e) {
+ JmsMessageCryptoUtil.logger.error("Unknown exception", e);
+ }
+ }
+
+ private static void generateKey() {
+ try {
+ final KeyGenerator kgen = KeyGenerator.getInstance("AES");
+ kgen.init(128);
+ final SecretKey skey = kgen.generateKey();
+ String key = Base64.encodeBase64String(skey.getEncoded());
+ System.out.println("Key: " + key);
+ } catch (final NoSuchAlgorithmException e) {
+ JmsMessageCryptoUtil.logger.error("Unknown encryption algorithm", e);
+ }
+ }
+
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/CommunicationFailureException.java b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/CommunicationFailureException.java
new file mode 100644
index 00000000..beb9d18d
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/CommunicationFailureException.java
@@ -0,0 +1,58 @@
+package de.taimos.dvalin.jms.exceptions;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class CommunicationFailureException extends InfrastructureException {
+ private static final long serialVersionUID = 5815412583044204150L;
+
+ private final CommunicationError communicationError;
+
+ /**
+ * @param communicationError of the exception
+ */
+ public CommunicationFailureException(CommunicationError communicationError) {
+ super(communicationError.getMsg());
+ this.communicationError = communicationError;
+ }
+
+ /**
+ * @param communicationError of the exception
+ * @param cause for the exception
+ */
+ public CommunicationFailureException(CommunicationError communicationError, Throwable cause) {
+ super(communicationError.getMsg(), cause);
+ this.communicationError = communicationError;
+ }
+
+ /**
+ * @return the communicationError
+ */
+ public CommunicationError getCommunicationError() {
+ return this.communicationError;
+ }
+
+ public static class CommunicationError {
+
+ public static final CommunicationError SEND = new CommunicationError("Error while sending messages");
+ public static final CommunicationError RECEIVE = new CommunicationError("Error while receiving messages");
+ public static final CommunicationError INVALID_RESPONSE = new CommunicationError(
+ "Invalid response message received");
+
+ private final String msg;
+
+ CommunicationError(String msg) {
+ this.msg = msg;
+ }
+
+ /**
+ * @return the msg
+ */
+ public String getMsg() {
+ return this.msg;
+ }
+ }
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/CreationException.java b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/CreationException.java
new file mode 100644
index 00000000..8cf935fd
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/CreationException.java
@@ -0,0 +1,61 @@
+package de.taimos.dvalin.jms.exceptions;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class CreationException extends InfrastructureException {
+
+ private static final long serialVersionUID = -1604742258978348120L;
+
+ private final Source exceptionSource;
+
+ /**
+ * @param exceptionSource source of the exception
+ * @param cause for the exception
+ */
+ public CreationException(Source exceptionSource, Throwable cause) {
+ super(exceptionSource.getMsg(), cause);
+ this.exceptionSource = exceptionSource;
+ }
+
+ /**
+ * @param exceptionSource source of the exception
+ */
+ public CreationException(Source exceptionSource) {
+ super(exceptionSource.getMsg());
+ this.exceptionSource = exceptionSource;
+ }
+
+ public static class Source {
+ public static final Source SESSION = new Source("Can not create session");
+ public static final Source CONNECTION = new Source("Can not create connection");
+ public static final Source DESTINATION = new Source("Can not create destination");
+ public static final Source REPLY_TO_DESTINATION = new Source("Can not create reply to destination");
+ public static final Source CONSUMER = new Source("Can not create consumer");
+ public static final Source PRODUCER = new Source("Can not create producer");
+ public static final Source FAILED_TO_CREATE_MESSAGE = new Source("Failed to create message");
+
+ private final String msg;
+
+ Source(String msg) {
+ this.msg = msg;
+ }
+
+ /**
+ * @return the msg
+ */
+ public String getMsg() {
+ return this.msg;
+ }
+ }
+
+ /**
+ * @return the exceptionSource
+ */
+ public Source getExceptionSource() {
+ return this.exceptionSource;
+ }
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/InfrastructureException.java b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/InfrastructureException.java
new file mode 100644
index 00000000..a60f8cc2
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/InfrastructureException.java
@@ -0,0 +1,62 @@
+package de.taimos.dvalin.jms.exceptions;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+/**
+ * Exception for all problems concerning the Interconnect infrastructure.
+ *
+ * @author thoeger
+ */
+public class InfrastructureException extends Exception {
+
+ /**
+ * version UID for serialization
+ */
+ private static final long serialVersionUID = 1L;
+
+
+ /**
+ * Default constructor.
+ */
+ public InfrastructureException() {
+ this("A problem with the Interconnect infrastructure occured", null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message a description of the problem
+ */
+ public InfrastructureException(String message) {
+ this(message, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message a description of the problem
+ * @param cause the cause of the problem
+ */
+ public InfrastructureException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/MessageCryptoException.java b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/MessageCryptoException.java
new file mode 100644
index 00000000..31585766
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/MessageCryptoException.java
@@ -0,0 +1,62 @@
+package de.taimos.dvalin.jms.exceptions;
+
+/*
+ * #%L
+ * Dvalin interconnect transfer data model
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+/**
+ * An exception for JMS message base crypto errors
+ *
+ * @author fzwirn
+ */
+public class MessageCryptoException extends SerializationException {
+
+
+ private static final long serialVersionUID = -6378917176126978412L;
+
+ /**
+ * default constructor
+ */
+ public MessageCryptoException() {
+ this("Message security check failed");
+ }
+
+ /**
+ * @param cause of the exception
+ */
+ public MessageCryptoException(Throwable cause) {
+ this("Message security check failed", cause);
+ }
+
+ /**
+ * @param message the exception message
+ */
+ public MessageCryptoException(String message) {
+ super(message);
+ }
+
+ /**
+ * @param message the exception message
+ * @param cause the root cause
+ */
+ public MessageCryptoException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/SerializationException.java b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/SerializationException.java
new file mode 100644
index 00000000..064b9db3
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/SerializationException.java
@@ -0,0 +1,62 @@
+package de.taimos.dvalin.jms.exceptions;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+/**
+ * Exception for all problems concerning the serialization or deserialization of data.
+ *
+ * @author thoeger
+ */
+public class SerializationException extends Exception {
+
+ /**
+ * version UID for serialization
+ */
+ private static final long serialVersionUID = 1L;
+
+
+ /**
+ * Default constructor.
+ */
+ public SerializationException() {
+ this("A problem occured during the serialization or deserialization of data.", null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message a description of the problem
+ */
+ public SerializationException(String message) {
+ this(message, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message a description of the problem
+ * @param cause the cause of the problem
+ */
+ public SerializationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/TimeoutException.java b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/TimeoutException.java
new file mode 100644
index 00000000..65f8bc2a
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/exceptions/TimeoutException.java
@@ -0,0 +1,40 @@
+package de.taimos.dvalin.jms.exceptions;
+
+/*
+ * #%L
+ * Dvalin interconnect core library
+ * %%
+ * Copyright (C) 2016 Taimos GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+/**
+ * Timeout exception
+ *
+ * @author thoeger
+ */
+public class TimeoutException extends InfrastructureException {
+
+ private static final long serialVersionUID = 1L;
+
+
+ /**
+ * @param timeout the timeout in millis
+ */
+ public TimeoutException(long timeout) {
+ super(String.format("Failed to receive a response within %d milliseconds.", timeout));
+ }
+
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/model/JmsContext.java b/jms/core/src/main/java/de/taimos/dvalin/jms/model/JmsContext.java
new file mode 100644
index 00000000..af64c1ac
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/model/JmsContext.java
@@ -0,0 +1,359 @@
+package de.taimos.dvalin.jms.model;
+
+import com.google.common.base.Preconditions;
+import de.taimos.dvalin.jms.IJmsConnector;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.jms.Destination;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class JmsContext {
+ public static class JmsContextBuilder extends AJmsContextBuilder {
+
+ /**
+ * @param body of the send request
+ * @return builder
+ */
+ @Nonnull
+ public JmsContextBuilder withBody(Serializable body) {
+ return super.withBody(body);
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ protected abstract static class AJmsContextBuilder> {
+
+ protected Destination destination;
+ protected String destinationName;
+ protected Serializable body;
+ protected Map headers = new HashMap<>();
+ protected boolean secure;
+ protected Destination replyToDestination;
+ protected String correlationId = UUID.randomUUID().toString();
+ protected JmsTarget target;
+ protected Long receiveTimeout = IJmsConnector.REQUEST_TIMEOUT;
+ protected Long timeToLive = IJmsConnector.REQUEST_TIMEOUT;
+ protected Integer priority = IJmsConnector.MSGPRIORITY;
+ protected String selector;
+ protected String replyToQueueName;
+
+ protected AJmsContextBuilder() {
+ //default constructor
+ }
+
+ public AJmsContextBuilder(JmsContext original) {
+ this.destination = original.destination;
+ this.destinationName = original.destinationName;
+ this.body = original.body;
+ this.headers = original.headers;
+ this.secure = original.secure;
+ this.replyToDestination = original.replyToDestination;
+ this.correlationId = original.correlationId;
+ this.target = original.target;
+ this.receiveTimeout = original.receiveTimeout;
+ this.timeToLive = original.timeToLive;
+ this.priority = original.priority;
+ this.selector = original.selector;
+ this.replyToQueueName = original.replyToQueueName;
+ }
+
+ /**
+ * @param destination for the send request
+ * @return builder
+ */
+ @Nonnull
+ public T withDestination(@Nullable Destination destination) {
+ this.destination = destination;
+ return (T) this;
+ }
+
+ /**
+ * @param destinationName name of the destination
+ * @return builder
+ */
+ @Nonnull
+ public T withDestinationName(@Nullable String destinationName) {
+ this.destinationName = destinationName;
+ return (T) this;
+ }
+
+ /**
+ * @param body of the send request
+ * @return builder
+ */
+ @Nonnull
+ protected T withBody(Serializable body) {
+ this.body = body;
+ return (T) this;
+ }
+
+ /**
+ * @param headers of the send request
+ * @return builder
+ */
+ @Nonnull
+ public T withHeaders(@Nonnull Map headers) {
+ this.headers.clear();
+ this.headers.putAll(headers);
+ return (T) this;
+ }
+
+ /**
+ * @param secure the connection or not
+ * @return builder
+ */
+ @Nonnull
+ public T withSecure(boolean secure) {
+ this.secure = secure;
+ return (T) this;
+ }
+
+ /**
+ * @param replyToDestination of the send request
+ * @return builder
+ */
+ @Nonnull
+ public T withReplyToDestination(@Nullable Destination replyToDestination) {
+ this.replyToDestination = replyToDestination;
+ return (T) this;
+ }
+
+ /**
+ * @param replyToQueueName of the send request
+ * @return builder
+ */
+ @Nonnull
+ public T withReplyToQueueName(@Nullable String replyToQueueName) {
+ this.replyToQueueName = replyToQueueName;
+ return (T) this;
+ }
+
+ /**
+ * @param correlationId of the send request
+ * @return builder
+ */
+ @Nonnull
+ public T withCorrelationId(@Nullable String correlationId) {
+ this.correlationId = correlationId;
+ return (T) this;
+ }
+
+ /**
+ * @param target ({@link JmsTarget#QUEUE}, {@link JmsTarget#TOPIC} or {@link JmsTarget#DESTINATION}) of the send request.
+ * For {@link JmsTarget#QUEUE} or {@link JmsTarget#TOPIC} the {@link #withDestinationName(String)} needs to be supplied.
+ * For {@link JmsTarget#DESTINATION} {@link #withDestination(Destination)} is required.
+ * @return builder
+ */
+ @Nonnull
+ public T withTarget(@Nonnull JmsTarget target) {
+ this.target = target;
+ return (T) this;
+ }
+
+ /**
+ * @param receiveTimeout of the send request
+ * @return builder
+ */
+ @Nonnull
+ public T withReceiveTimeout(Long receiveTimeout, @Nullable TimeUnit timeUnit) {
+ if (receiveTimeout != null && timeUnit != null) {
+ this.receiveTimeout = timeUnit.toMillis(receiveTimeout);
+ } else if (receiveTimeout != null) {
+ this.receiveTimeout = receiveTimeout;
+ }
+ return (T) this;
+ }
+
+ /**
+ * @param timeToLive of the send request
+ * @return builder
+ */
+ @Nonnull
+ public T withTimeToLive(Long timeToLive, @Nullable TimeUnit timeUnit) {
+ if (timeToLive != null && timeUnit != null) {
+ this.timeToLive = timeUnit.toMillis(timeToLive);
+ } else if (timeToLive != null) {
+ this.timeToLive = timeToLive;
+ }
+ return (T) this;
+ }
+
+ /**
+ * @param priority of the send request
+ * @return builder
+ */
+ @Nonnull
+ public T withPriority(@Nullable Integer priority) {
+ this.priority = priority;
+ return (T) this;
+ }
+
+ /**
+ * @return an instance of the JmsContext filled with the context of the builder
+ */
+ @Nonnull
+ public JmsContext build() {
+ this.validate();
+ if (this.selector == null) {
+ this.selector = "JMSCorrelationID = '" + this.correlationId + "'";
+ }
+
+ return new JmsContext(this);
+ }
+
+ protected void validate() {
+ Preconditions.checkNotNull(this.target, "JMS Target not set");
+ switch (this.target) {
+ case DESTINATION:
+ Preconditions.checkNotNull(this.destination, "Destination was null");
+ break;
+ case QUEUE:
+ Preconditions.checkNotNull(this.destinationName, "Queue name was null");
+ break;
+ case TOPIC:
+ Preconditions.checkNotNull(this.destinationName, "Topic name was null");
+ break;
+ case RECEPTION_CONTEXT:
+ break;
+ default:
+ throw new UnsupportedOperationException("Target not supported: " + this.target);
+ }
+ Preconditions.checkNotNull(this.body, "Body was null");
+ }
+ }
+
+ private final Destination destination;
+ private final String destinationName;
+ private final Serializable body;
+ private final Map headers;
+ private final boolean secure;
+ private final Destination replyToDestination;
+ private final String correlationId;
+ private final JmsTarget target;
+ private final Long receiveTimeout;
+ private final Long timeToLive;
+ private final Integer priority;
+
+ private final String replyToQueueName;
+ private final String selector;
+
+ protected JmsContext(AJmsContextBuilder> builder) {
+ this.destination = builder.destination;
+ this.destinationName = builder.destinationName;
+ this.body = builder.body;
+ this.headers = builder.headers;
+ this.secure = builder.secure;
+ this.replyToDestination = builder.replyToDestination;
+ this.correlationId = builder.correlationId;
+ this.target = builder.target;
+ this.receiveTimeout = builder.receiveTimeout;
+ this.timeToLive = builder.timeToLive;
+ this.priority = builder.priority;
+ this.replyToQueueName = builder.replyToQueueName;
+ this.selector = builder.selector;
+ }
+
+ /**
+ * @return the destination
+ */
+ public Destination getDestination() {
+ return this.destination;
+ }
+
+ /**
+ * @return the body
+ */
+ public Serializable getBody() {
+ return this.body;
+ }
+
+ /**
+ * @return the headers
+ */
+ public Map getHeaders() {
+ return this.headers;
+ }
+
+ /**
+ * @return the secure
+ */
+ public boolean isSecure() {
+ return this.secure;
+ }
+
+ /**
+ * @return the replyToQueueName
+ */
+ public String getReplyToQueueName() {
+ return this.replyToDestination != null ? this.replyToDestination.toString() : this.replyToQueueName;
+ }
+
+ /**
+ * @return the replyToDestination
+ */
+ public Destination getReplyToDestination() {
+ return this.replyToDestination;
+ }
+
+ /**
+ * @return the correlationId
+ */
+ public String getCorrelationId() {
+ return this.correlationId;
+ }
+
+ /**
+ * @return the target
+ */
+ @Nonnull
+ public JmsTarget getTarget() {
+ return this.target;
+ }
+
+ /**
+ * @return the destinationName
+ */
+ public String getDestinationName() {
+ return this.destinationName;
+ }
+
+ /**
+ * @return the receiveTimeout
+ */
+ public long getReceiveTimeout() {
+ return this.receiveTimeout;
+ }
+
+ /**
+ * @return the timeToLive
+ */
+ public long getTimeToLive() {
+ return this.timeToLive;
+ }
+
+ /**
+ * @return the priority
+ */
+ public int getPriority() {
+ return this.priority;
+ }
+
+ /**
+ * @return the selector
+ */
+ public String getSelector() {
+ return this.selector;
+ }
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/model/JmsResponseContext.java b/jms/core/src/main/java/de/taimos/dvalin/jms/model/JmsResponseContext.java
new file mode 100644
index 00000000..8c777a8e
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/model/JmsResponseContext.java
@@ -0,0 +1,31 @@
+package de.taimos.dvalin.jms.model;
+
+
+import javax.annotation.Nonnull;
+import javax.jms.Message;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class JmsResponseContext {
+
+ private final T receivedTextMessage;
+
+ /**
+ * @param receivedTextMessage of the response
+ */
+ public JmsResponseContext(@Nonnull T receivedTextMessage) {
+ this.receivedTextMessage = receivedTextMessage;
+ }
+
+ /**
+ * @return the textMessage
+ */
+ @Nonnull
+ public T getReceivedMessage() {
+ return this.receivedTextMessage;
+ }
+}
diff --git a/jms/core/src/main/java/de/taimos/dvalin/jms/model/JmsTarget.java b/jms/core/src/main/java/de/taimos/dvalin/jms/model/JmsTarget.java
new file mode 100644
index 00000000..b2858ceb
--- /dev/null
+++ b/jms/core/src/main/java/de/taimos/dvalin/jms/model/JmsTarget.java
@@ -0,0 +1,16 @@
+package de.taimos.dvalin.jms.model;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public enum JmsTarget {
+ DESTINATION,
+ QUEUE,
+ TEMPORARY_QUEUE,
+ TOPIC,
+ TEMPORARY_TOPIC,
+ RECEPTION_CONTEXT
+}
diff --git a/interconnect/model/src/test/java/de/taimos/dvalin/interconnect/model/common/MessageCryptoUtilTest.java b/jms/core/src/test/java/de/taimos/dvalin/jms/crypto/MessageCryptoUtilTest.java
similarity index 54%
rename from interconnect/model/src/test/java/de/taimos/dvalin/interconnect/model/common/MessageCryptoUtilTest.java
rename to jms/core/src/test/java/de/taimos/dvalin/jms/crypto/MessageCryptoUtilTest.java
index 7d338144..9d5c8678 100644
--- a/interconnect/model/src/test/java/de/taimos/dvalin/interconnect/model/common/MessageCryptoUtilTest.java
+++ b/jms/core/src/test/java/de/taimos/dvalin/jms/crypto/MessageCryptoUtilTest.java
@@ -1,7 +1,7 @@
/**
*
*/
-package de.taimos.dvalin.interconnect.model.common;
+package de.taimos.dvalin.jms.crypto;
/*
* #%L
@@ -23,28 +23,26 @@
* #L%
*/
-import de.taimos.dvalin.interconnect.model.CryptoException;
-import de.taimos.dvalin.interconnect.model.InterconnectConstants;
-import de.taimos.dvalin.interconnect.model.MessageCryptoUtil;
+import de.taimos.dvalin.jms.exceptions.MessageCryptoException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class MessageCryptoUtilTest {
- /**
- * @throws CryptoException -
- */
- @Test
- void crypt() throws CryptoException {
- System.setProperty(InterconnectConstants.PROPERTY_CRYPTO_AESKEY, "4b5c6acc6cedc3093d7ad49d195af14a");
- System.setProperty(InterconnectConstants.PROPERTY_CRYPTO_SIGNATURE, "8602266778973c0edd198713985b9e56");
+ /**
+ * @throws MessageCryptoException -
+ */
+ @Test
+ void crypt() throws MessageCryptoException {
+ System.setProperty(JmsMessageCryptoUtil.PROPERTY_CRYPTO_AESKEY, "4b5c6acc6cedc3093d7ad49d195af14a");
+ System.setProperty(JmsMessageCryptoUtil.PROPERTY_CRYPTO_SIGNATURE, "8602266778973c0edd198713985b9e56");
- // i'm curious ;)
+ // i'm curious ;)
// TODO: 17.02.16 fix umlauts in docker release environment
// String data = "hallali lö lä lü li";
- String data = "hallali li li li li";
- String crypt = MessageCryptoUtil.crypt(data);
- String decrypt = MessageCryptoUtil.decrypt(crypt);
- Assertions.assertEquals(data, decrypt);
- }
+ String data = "hallali li li li li";
+ String crypt = JmsMessageCryptoUtil.crypt(data);
+ String decrypt = JmsMessageCryptoUtil.decrypt(crypt);
+ Assertions.assertEquals(data, decrypt);
+ }
}
diff --git a/jms/jms-test/pom.xml b/jms/jms-test/pom.xml
new file mode 100644
index 00000000..2d43519d
--- /dev/null
+++ b/jms/jms-test/pom.xml
@@ -0,0 +1,38 @@
+
+
+ 4.0.0
+
+ de.taimos
+ dvalin-parent
+ 1.36-SNAPSHOT
+ ../../pom.xml
+
+
+ dvalin-jms-test
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+
+
+ de.taimos
+ dvalin-jms-core
+ ${project.version}
+ compile
+
+
+
+ de.taimos
+ dvalin-daemon
+ ${project.version}
+
+
+
+
\ No newline at end of file
diff --git a/jms/jms-test/src/main/java/de/taimos/dvalin/jms/test/JmsConnectorMock.java b/jms/jms-test/src/main/java/de/taimos/dvalin/jms/test/JmsConnectorMock.java
new file mode 100644
index 00000000..7442d8e9
--- /dev/null
+++ b/jms/jms-test/src/main/java/de/taimos/dvalin/jms/test/JmsConnectorMock.java
@@ -0,0 +1,64 @@
+package de.taimos.dvalin.jms.test;
+
+import de.taimos.dvalin.jms.IJmsConnector;
+import de.taimos.dvalin.jms.model.JmsContext;
+import de.taimos.dvalin.jms.model.JmsResponseContext;
+
+import javax.annotation.Nonnull;
+import javax.jms.Message;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+@SuppressWarnings("unused")
+public class JmsConnectorMock implements IJmsConnector {
+
+ private final List receivedContext = Collections.synchronizedList(new ArrayList<>());
+
+ @Override
+ public void send(@Nonnull JmsContext context) {
+ this.receivedContext.add(context);
+ }
+
+ @Override
+ public JmsResponseContext extends Message> request(@Nonnull JmsContext context) {
+ this.receivedContext.add(context);
+ return null;
+ }
+
+ @Override
+ public JmsResponseContext extends Message> receive(@Nonnull JmsContext context) {
+ this.receivedContext.add(context);
+ return null;
+ }
+
+ @Override
+ public List receiveBulkFromDestination(JmsContext context, int maxSize) {
+ this.receivedContext.add(context);
+ return Collections.emptyList();
+ }
+
+ /**
+ * @return the receivedContext
+ */
+ public List getReceivedContext() {
+ synchronized (this.receivedContext) {
+ return this.receivedContext;
+ }
+ }
+
+ /**
+ * clear the received context
+ */
+ public void clearReceivedContext() {
+ synchronized (this.receivedContext) {
+ this.receivedContext.clear();
+ }
+ }
+}
diff --git a/jms/jms-test/src/main/java/de/taimos/dvalin/jms/test/TestCryptoService.java b/jms/jms-test/src/main/java/de/taimos/dvalin/jms/test/TestCryptoService.java
new file mode 100644
index 00000000..e6171e3a
--- /dev/null
+++ b/jms/jms-test/src/main/java/de/taimos/dvalin/jms/test/TestCryptoService.java
@@ -0,0 +1,13 @@
+package de.taimos.dvalin.jms.test;
+
+import de.taimos.dvalin.jms.crypto.ACryptoService;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+public class TestCryptoService extends ACryptoService {
+ // Uses default implemenation
+}
diff --git a/jms/jms-test/src/main/java/de/taimos/dvalin/jms/test/config/JmsTestConfig.java b/jms/jms-test/src/main/java/de/taimos/dvalin/jms/test/config/JmsTestConfig.java
new file mode 100644
index 00000000..0cd3beb4
--- /dev/null
+++ b/jms/jms-test/src/main/java/de/taimos/dvalin/jms/test/config/JmsTestConfig.java
@@ -0,0 +1,31 @@
+package de.taimos.dvalin.jms.test.config;
+
+import de.taimos.dvalin.jms.IJmsConnector;
+import de.taimos.dvalin.jms.crypto.ICryptoService;
+import de.taimos.dvalin.jms.test.JmsConnectorMock;
+import de.taimos.dvalin.jms.test.TestCryptoService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+/**
+ * Copyright 2024 Cinovo AG
+ *
+ *
+ * @author fzwirn
+ */
+@Configuration
+@Profile(de.taimos.daemon.spring.Configuration.PROFILES_TEST)
+public class JmsTestConfig {
+
+
+ @Bean
+ IJmsConnector jmsConnector() {
+ return new JmsConnectorMock();
+ }
+
+ @Bean
+ ICryptoService cryptoService() {
+ return new TestCryptoService();
+ }
+}
diff --git a/jms/pom.xml b/jms/pom.xml
new file mode 100644
index 00000000..b0ec4da3
--- /dev/null
+++ b/jms/pom.xml
@@ -0,0 +1,24 @@
+
+
+ 4.0.0
+
+ de.taimos
+ dvalin-parent
+ 1.36-SNAPSHOT
+
+ dvalin-jms-parent
+ pom
+ JMS interfacing for dvalin
+ 2024
+
+
+
+
+
+ core
+ jms-test
+ activemq-classic
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 6e2ef47f..dd58c7d8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -661,5 +661,6 @@
interconnect
i18n
archetypes
+ jms