aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/gv
diff options
context:
space:
mode:
authorChristof Rabensteiner <christof.rabensteiner@iaik.tugraz.at>2019-07-12 15:40:05 +0200
committerChristof Rabensteiner <christof.rabensteiner@iaik.tugraz.at>2019-07-12 15:40:05 +0200
commit25d68c8900c2cc791f03ea3db173955ca237fd55 (patch)
treef4d28b97845d10a709590dce480195b322ba019b /src/main/java/at/gv
parent9dc0e72571a895e34a55c11d015c5d359b485aff (diff)
downloadmoa-zs-25d68c8900c2cc791f03ea3db173955ca237fd55.tar.gz
moa-zs-25d68c8900c2cc791f03ea3db173955ca237fd55.tar.bz2
moa-zs-25d68c8900c2cc791f03ea3db173955ca237fd55.zip
Allow App To Choose Between MsgResponse Sinks
- MZS Schema Change: Add "MsgResponseSinks" element to mzs:DeliveryRequest/Config that allows sender to configure how MsgResponses should be archived. - ConfigUtil: Interpret MsgResponseSink parameters from Spring Environment and merge with ConfigType. - MsgResponseBackend: Send responses to sinks according to MsgResponseSinks in Config - application.yaml: Add MsgResponseSinks parameter to configuration. - Uncouple Sink implementations from java.util.function.Function, because the sink interfaces are going to differ and there is no need to unite them under one interface. - Add and test LogResponseSink, which logs responses to it's logger. - MsgResponse: Add JAXB getter for response. Reason: Can be passed to marshaller.
Diffstat (limited to 'src/main/java/at/gv')
-rw-r--r--src/main/java/at/gv/egiz/moazs/backend/LogResponseSink.java44
-rw-r--r--src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java41
-rw-r--r--src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java14
-rw-r--r--src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java62
-rw-r--r--src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java7
-rw-r--r--src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java9
-rw-r--r--src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java10
7 files changed, 166 insertions, 21 deletions
diff --git a/src/main/java/at/gv/egiz/moazs/backend/LogResponseSink.java b/src/main/java/at/gv/egiz/moazs/backend/LogResponseSink.java
new file mode 100644
index 0000000..d419944
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/backend/LogResponseSink.java
@@ -0,0 +1,44 @@
+package at.gv.egiz.moazs.backend;
+
+import at.gv.egiz.moazs.scheme.Marshaller;
+import at.gv.egiz.moazs.scheme.MsgResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.CompletableFuture;
+
+import static java.util.concurrent.CompletableFuture.completedFuture;
+
+@Component
+public class LogResponseSink {
+
+ private static final Logger log = LoggerFactory.getLogger(LogResponseSink.class);
+ private static final String LOG_LEVEL_WARN_MESSAGE = "Will not log response because INFO level is disabled.";
+
+ private final Marshaller msgMarshaller;
+
+ public LogResponseSink(Marshaller msgMarshaller) {
+ this.msgMarshaller = msgMarshaller;
+ }
+
+ /**
+ * Log response to class logger at level=INFO.
+ *
+ * @param msgResponse
+ * @return
+ */
+ public CompletableFuture<Void> log(MsgResponse msgResponse) {
+
+ if(log.isInfoEnabled()) {
+ var builder = new StringBuilder("Received the following Message: \n");
+ builder.append(msgMarshaller.marshallXml(msgResponse.getResponseAsJAXBElement()));
+ log.info(builder.toString());
+ } else {
+ log.warn(LOG_LEVEL_WARN_MESSAGE);
+ }
+
+ return completedFuture(null);
+
+ }
+}
diff --git a/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java b/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java
index 414c2dc..1b17f34 100644
--- a/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java
+++ b/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java
@@ -4,14 +4,13 @@ import at.gv.egiz.moazs.MoaZSException;
import at.gv.egiz.moazs.repository.DeliveryRepository;
import at.gv.egiz.moazs.scheme.MsgResponse;
import at.gv.egiz.moazs.service.MsgService;
+import at.gv.zustellung.app2mzs.xsd.MsgResponseSinksType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
-import java.util.function.Function;
import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder;
import static java.lang.String.format;
@@ -27,29 +26,38 @@ public class MsgResponseBackend implements Consumer<String> {
private final DeliveryRepository repository;
private final Consumer<byte[]> signatureVerifier;
- private final Function<MsgResponse, CompletableFuture<Void>> sink;
+ private final SaveResponseToFileSink saveResponseToFileSink;
+ private final LogResponseSink logResponseSink;
@Autowired
public MsgResponseBackend(DeliveryRepository repository,
Consumer<byte[]> signatureVerifier,
- Function<MsgResponse, CompletableFuture<Void>> sink) {
+ SaveResponseToFileSink saveResponseToFileSink,
+ LogResponseSink logResponseSink) {
this.repository = repository;
this.signatureVerifier = signatureVerifier;
- this.sink = sink;
+ this.saveResponseToFileSink = saveResponseToFileSink;
+ this.logResponseSink = logResponseSink;
}
/**
* Performs all {@code MsgResponse}'s Back-End Tasks, such as verifying
* its signature and archiving the response.
*
+ * Note: When the signature verification fails, this method will not archive
+ * the original response (the one that was received from msg) to the sink,
+ * but an error message.
+ *
* @param responseID refers to MsgResponse Object.
*/
@Override
public void accept(String responseID) {
- supplyAsync(() -> verify(responseID)).thenAcceptAsync(sink::apply);
+
+ supplyAsync(() -> verify(responseID))
+ .thenAcceptAsync(msgResponse -> applySinks(msgResponse));
}
- public MsgResponse verify(String responseID) {
+ private MsgResponse verify(String responseID) {
var response = repository.retrieveResponse(responseID).get();
var builder = moaZSExceptionBuilder().withAllParametersInAnswer(response.getAnswer());
@@ -72,4 +80,23 @@ public class MsgResponseBackend implements Consumer<String> {
}
+ private void applySinks(MsgResponse msgResponse) {
+
+ var sinkParams = getSinkParams(msgResponse);
+
+ if (sinkParams.isSafeResponseToFile()) {
+ supplyAsync(() -> saveResponseToFileSink.save(msgResponse));
+ }
+
+ if (sinkParams.isLogResponse()) {
+ supplyAsync(() -> logResponseSink.log(msgResponse));
+ }
+ }
+
+ private MsgResponseSinksType getSinkParams(MsgResponse msgResponse) {
+ var appDeliveryID = msgResponse.getAppDeliveryID();
+ var request = repository.retrieveDeliveryRequest(appDeliveryID).get();
+ return request.getConfig().getMsgResponseSinks();
+ }
+
}
diff --git a/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java b/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java
index 02771a9..7da76ef 100644
--- a/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java
+++ b/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java
@@ -15,7 +15,6 @@ import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CompletableFuture;
-import java.util.function.Function;
import static at.gv.egiz.moazs.MoaZSException.moaZSException;
import static java.lang.String.format;
@@ -23,10 +22,11 @@ import static java.util.concurrent.CompletableFuture.allOf;
import static java.util.concurrent.CompletableFuture.supplyAsync;
@Component
-public class SaveResponseToFileSink implements Function<MsgResponse, CompletableFuture<Void>> {
+public class SaveResponseToFileSink {
private static final Logger log = LoggerFactory.getLogger(SaveResponseToFileSink.class);
private static final String SAVING_FAILED_MSG = "Could not save response with AppDeliveryId=%s.";
+ private static final String SAVE_RESPONSE_MSG = "Saving response to {}..." ;
private final SimpleDateFormat isoFormatter;
private final Marshaller msgMarshaller;
@@ -41,8 +41,13 @@ public class SaveResponseToFileSink implements Function<MsgResponse, Completable
this.isoFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
}
- @Override
- public CompletableFuture<Void> apply(MsgResponse response) {
+ /**
+ * Save response and it's binary version to the file system.
+ *
+ * @param response
+ * @return Future that completes when both responses have been written to the file system.
+ */
+ public CompletableFuture<Void> save(MsgResponse response) {
var responseID = response.getResponseID();
@@ -79,6 +84,7 @@ public class SaveResponseToFileSink implements Function<MsgResponse, Completable
}
private void storeToFile(String path, byte[] content) {
+ log.trace(SAVE_RESPONSE_MSG, path);
try {
FileUtils.writeByteArrayToFile(new File(path), content);
} catch (IOException e) {
diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java
index 68f833e..9cdc07a 100644
--- a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java
+++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java
@@ -1,10 +1,7 @@
package at.gv.egiz.moazs.preprocess;
import at.gv.egiz.moazs.util.StringUtils;
-import at.gv.zustellung.app2mzs.xsd.ClientType;
-import at.gv.zustellung.app2mzs.xsd.ConfigType;
-import at.gv.zustellung.app2mzs.xsd.KeyStoreType;
-import at.gv.zustellung.app2mzs.xsd.SSLType;
+import at.gv.zustellung.app2mzs.xsd.*;
import org.springframework.stereotype.Component;
import java.math.BigInteger;
@@ -13,6 +10,7 @@ import java.util.Map;
import static at.gv.zustellung.app2mzs.xsd.ClientType.clientTypeBuilder;
import static at.gv.zustellung.app2mzs.xsd.ConfigType.configTypeBuilder;
import static at.gv.zustellung.app2mzs.xsd.KeyStoreType.keyStoreTypeBuilder;
+import static at.gv.zustellung.app2mzs.xsd.MsgResponseSinksType.msgResponseSinksTypeBuilder;
import static at.gv.zustellung.app2mzs.xsd.SSLType.SSLTypeBuilder;
import static java.util.stream.Collectors.toMap;
@@ -33,7 +31,9 @@ public class ConfigUtil {
public static final String PASSWORD_KEY = "password";
public static final String RECEIVE_TIMEOUT = "receive-timeout";
public static final String CONNECTION_TIMEOUT_KEY = "connection-timeout";
-
+ public static final String MSG_RESPONSE_SINKS_KEY = "msg-response-sinks";
+ public static final String LOG_RESPONSE_KEY = "log-response";
+ public static final String SAVE_RESPONSE_TO_FILE_KEY = "save-response-to-file";
/**
* Convert a map into a Config object.
@@ -53,10 +53,15 @@ public class ConfigUtil {
ClientType tnvzClient = tnvzClientParams.isEmpty()
? null : buildClient(tnvzClientParams);
+ var msgResponseSinksParams = filterMapByPrefix(values, MSG_RESPONSE_SINKS_KEY);
+ MsgResponseSinksType sinks = msgResponseSinksParams.isEmpty()
+ ? null : buildMsgResponseSinks(msgResponseSinksParams);
+
return ConfigType.configTypeBuilder()
.withPerformQueryPersonRequest(performQueryPersonRequest)
.withMSGClient(msgClient)
.withTNVZClient(tnvzClient)
+ .withMsgResponseSinks(sinks)
.build();
}
@@ -102,11 +107,8 @@ public class ConfigUtil {
KeyStoreType trustStore = trustStoreParams.isEmpty()
? null : buildKeyStore(trustStoreParams);
- var trustAll = sslParams.get(TRUST_ALL_KEY) == null
- ? null : Boolean.getBoolean(sslParams.get(TRUST_ALL_KEY));
-
- var laxHostNameVerification = sslParams.get(LAX_HOSTNAME_VERIFICATION_KEY) == null
- ? null : Boolean.getBoolean(sslParams.get(LAX_HOSTNAME_VERIFICATION_KEY));
+ var trustAll = booleanOrNull(sslParams.get(TRUST_ALL_KEY));
+ var laxHostNameVerification = booleanOrNull(sslParams.get(LAX_HOSTNAME_VERIFICATION_KEY));
return SSLTypeBuilder()
.withKeyStore(keyStore)
@@ -126,6 +128,22 @@ public class ConfigUtil {
.build();
}
+ private MsgResponseSinksType buildMsgResponseSinks(Map<String, String> params) {
+
+ var logResponse = booleanOrNull(params.get(LOG_RESPONSE_KEY));
+ var saveResponse = booleanOrNull(params.get(SAVE_RESPONSE_TO_FILE_KEY));
+
+ return msgResponseSinksTypeBuilder()
+ .withLogResponse(logResponse)
+ .withLogResponse(saveResponse)
+ .build();
+ }
+
+ private Boolean booleanOrNull(String value) {
+ return value == null ? null : Boolean.getBoolean(value);
+ }
+
+
/**
* Combine properties of two Configs; {@code primary} overrides {@code fallback}.
*
@@ -149,6 +167,10 @@ public class ConfigUtil {
builder.withMSGClient(merge(primary.getTNVZClient(), fallback.getTNVZClient()));
}
+ if (primary.getMsgResponseSinks() != null) {
+ builder.withMsgResponseSinks(merge(primary.getMsgResponseSinks(), fallback.getMsgResponseSinks()));
+ }
+
return builder.build();
}
@@ -214,4 +236,24 @@ public class ConfigUtil {
}
+ private MsgResponseSinksType merge(MsgResponseSinksType primary, MsgResponseSinksType fallback) {
+
+ if (fallback == null) {
+ return primary;
+ }
+
+ var builder = msgResponseSinksTypeBuilder(fallback);
+
+ if (primary.isLogResponse() != null) {
+ builder.withLogResponse(primary.isLogResponse());
+ }
+
+ if (primary.isSafeResponseToFile() != null) {
+ builder.withLogResponse(primary.isSafeResponseToFile());
+ }
+
+ return builder.build();
+ }
+
+
}
diff --git a/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java b/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java
index 80e2059..5370448 100644
--- a/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java
+++ b/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java
@@ -3,6 +3,12 @@ package at.gv.egiz.moazs.scheme;
import at.gv.egiz.moazs.MoaZSException;
import at.gv.zustellung.msg.xsd.DeliveryAnswerType;
+import javax.xml.bind.JAXBElement;
+
+/**
+ * Represents responses to DeliveryRequests that were received from the msg service.
+ * @param <T> The type of the response.
+ */
public abstract class MsgResponse <T> {
protected String id;
@@ -20,6 +26,7 @@ public abstract class MsgResponse <T> {
}
public abstract T getResponse();
+ public abstract JAXBElement<T> getResponseAsJAXBElement();
public abstract String getAppDeliveryID();
public abstract String getZSDeliveryID();
public abstract DeliveryAnswerType getAnswer();
diff --git a/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java b/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java
index de1fd38..784d000 100644
--- a/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java
+++ b/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java
@@ -3,6 +3,9 @@ package at.gv.egiz.moazs.scheme;
import at.gv.egiz.moazs.MoaZSException;
import at.gv.zustellung.msg.xsd.DeliveryAnswerType;
import at.gv.zustellung.msg.xsd.DeliveryNotificationType;
+import at.gv.zustellung.msg.xsd.ObjectFactory;
+
+import javax.xml.bind.JAXBElement;
import static at.gv.zustellung.msg.xsd.DeliveryNotificationType.deliveryNotificationTypeBuilder;
@@ -10,6 +13,7 @@ public class NotificationResponse extends MsgResponse<DeliveryNotificationType>
private final DeliveryNotificationType notification;
private static final String ID_SUFFIX = ".NO";
+ private static final ObjectFactory factory = new ObjectFactory();
public NotificationResponse(DeliveryNotificationType notification) {
super.id = createResponseId(notification.getAppDeliveryID(), ID_SUFFIX);
@@ -26,6 +30,11 @@ public class NotificationResponse extends MsgResponse<DeliveryNotificationType>
}
@Override
+ public JAXBElement<DeliveryNotificationType> getResponseAsJAXBElement() {
+ return factory.createDeliveryNotification(notification);
+ }
+
+ @Override
public String getAppDeliveryID() {
return notification.getAppDeliveryID();
}
diff --git a/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java b/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java
index 0705698..3b4710b 100644
--- a/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java
+++ b/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java
@@ -4,6 +4,9 @@ import at.gv.egiz.moazs.MoaZSException;
import at.gv.zustellung.msg.xsd.DeliveryAnswerType;
import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType;
import at.gv.zustellung.msg.xsd.ErrorInfoType;
+import at.gv.zustellung.msg.xsd.ObjectFactory;
+
+import javax.xml.bind.JAXBElement;
import static at.gv.egiz.moazs.util.NullCoalesce.coalesce;
import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Error.errorBuilder;
@@ -15,6 +18,8 @@ public class RequestStatusResponse extends MsgResponse<DeliveryRequestStatusType
private final DeliveryRequestStatusType status;
private final DeliveryAnswerType answer;
private static final String ID_SUFFIX = ".RS";
+ private static final ObjectFactory factory = new ObjectFactory();
+
public RequestStatusResponse(DeliveryRequestStatusType status) {
this.status = status;
@@ -32,6 +37,11 @@ public class RequestStatusResponse extends MsgResponse<DeliveryRequestStatusType
}
@Override
+ public JAXBElement<DeliveryRequestStatusType> getResponseAsJAXBElement() {
+ return factory.createDeliveryRequestStatus(status);
+ }
+
+ @Override
public String getAppDeliveryID() {
return answer.getAppDeliveryID();
}