argos/notification-service/notification/src/main/java/gr/cite/notification/service/message/common/MessageBuilderBase.java

306 lines
12 KiB
Java

package gr.cite.notification.service.message.common;
import gr.cite.notification.cache.NotificationTemplateCache;
import gr.cite.notification.common.StringUtils;
import gr.cite.notification.common.types.notification.FieldInfo;
import gr.cite.notification.config.notification.NotificationProperties;
import gr.cite.notification.errorcode.ErrorThesaurusProperties;
import gr.cite.notification.model.notificationtemplate.FieldOptions;
import gr.cite.notification.service.formatting.FormattingService;
import gr.cite.notification.service.message.model.MessageInfo;
import gr.cite.tools.cipher.CipherService;
import gr.cite.tools.cipher.config.CipherProfileProperties;
import gr.cite.tools.exception.MyApplicationException;
import gr.cite.tools.logging.LoggerService;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.Instant;
import java.util.*;
public abstract class MessageBuilderBase {
private final LoggerService logger;
private final ErrorThesaurusProperties errors;
private final CipherService cipherService;
private final CipherProfileProperties cipherProfileProperties;
private final FormattingService formattingService;
private final NotificationTemplateCache cache;
public MessageBuilderBase(LoggerService logger, ErrorThesaurusProperties errors, CipherService cipherService, CipherProfileProperties cipherProfileProperties, FormattingService formattingService, NotificationTemplateCache cache) {
this.logger = logger;
this.errors = errors;
this.cipherService = cipherService;
this.cipherProfileProperties = cipherProfileProperties;
this.formattingService = formattingService;
this.cache = cache;
}
//GK: Unlike in C# in Java Map is just an interface
protected static class FieldFormatting extends HashMap<String, String> {
public Boolean isSet(String key) {
return this.containsKey(key) && (this.get(key) != null && !this.get(key).isEmpty());
}
}
public static class FieldCiphering extends HashSet<String> {
public FieldCiphering(List<String> cipherFields) {
super(cipherFields);
}
public FieldCiphering() {
}
public Boolean isSet(String key) {
return this.contains(key);
}
}
protected static class ReplaceResult {
private String text;
private Set<String> replacedKeys;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Set<String> getReplacedKeys() {
return replacedKeys;
}
public void setReplacedKeys(Set<String> replacedKeys) {
this.replacedKeys = replacedKeys;
}
}
protected ReplaceResult applyFieldReplace(String text, MessageInfo messageInfo, FieldFormatting fieldFormatting, FieldCiphering fieldCiphering) {
ReplaceResult result = new ReplaceResult();
result.setReplacedKeys(new HashSet<>());
if (messageInfo.getUserId() != null && (fieldCiphering != null && !fieldCiphering.isSet("{user-id}"))) {
String txtValue = fieldFormatting.isSet("{user-id}") ? String.format(fieldFormatting.get("{user-id}"), messageInfo.getUserId().toString()) : messageInfo.getUserId().toString();
text = text.replace("{user-id}", txtValue);
result.getReplacedKeys().add("{user-id}");
}
//GOTCHA: fieldCiphering not supported for language-code. will not replace
if (!StringUtils.isNullOrEmpty(messageInfo.getLanguage()) && (fieldCiphering != null && !fieldCiphering.isSet("{language-code}"))) {
String txtValue = fieldFormatting.isSet("{language-code}") ? String.format(fieldFormatting.get("{language-code}"), messageInfo.getLanguage()) : messageInfo.getLanguage();
text = text.replace("{language-code}", txtValue);
result.getReplacedKeys().add("{language-code}");
}
//GOTCHA: fieldCiphering not supported for language-code. will not replace
if (!StringUtils.isNullOrEmpty(messageInfo.getCulture()) && (fieldCiphering != null && !fieldCiphering.isSet("{culture-code}"))) {
String txtValue = fieldFormatting.isSet("{culture-code}") ? String.format(fieldFormatting.get("{culture-code}"), messageInfo.getCulture()) : messageInfo.getCulture();
text = text.replace("{culture-code}", txtValue);
result.getReplacedKeys().add("{culture-code}");
}
//GOTCHA: fieldCiphering not supported for timezone-code. will not replace
if (!StringUtils.isNullOrEmpty(messageInfo.getTimeZone()) && (fieldCiphering != null && !fieldCiphering.isSet("{timezone-code}"))) {
String txtValue = fieldFormatting.isSet("{timezone-code}") ? String.format(fieldFormatting.get("{timezone-code}"), messageInfo.getTimeZone()) : messageInfo.getTimeZone();
text = text.replace("{timezone-code}", txtValue);
result.getReplacedKeys().add("{timezone-code}");
}
//GOTCHA: fieldCiphering not supported for tenant-id. will not replace
if (messageInfo.getTenantId() !=null && !messageInfo.getTenantId().equals(new UUID(0L, 0L)) && (fieldCiphering != null && !fieldCiphering.isSet("{tenant-id}"))) {
String txtValue = fieldFormatting.isSet("{tenant-id}") ? String.format(fieldFormatting.get("{tenant-id}"), messageInfo.getTenantId().toString()) : messageInfo.getTenantId().toString();
text = text.replace("{tenant-id}", txtValue);
result.getReplacedKeys().add("{tenant-id}");
}
//GOTCHA: fieldCiphering not supported for tenant-code. will not replace
if (!StringUtils.isNullOrEmpty(messageInfo.getTenantCode()) && (fieldCiphering != null && !fieldCiphering.isSet("{tenant-code}"))) {
String txtValue = fieldFormatting.isSet("{tenant-code}") ? String.format(fieldFormatting.get("{tenant-code}"), messageInfo.getTenantCode()) : messageInfo.getTenantCode();
text = text.replace("{tenant-code}", txtValue);
result.getReplacedKeys().add("{tenant-code}");
}
for (FieldInfo field : messageInfo.getFields()) {
FieldInfo theField = field;
if ((fieldCiphering != null && fieldCiphering.isSet(field.getKey())) && !StringUtils.isNullOrEmpty(field.getValue())) {
theField = new FieldInfo();
theField.setKey(field.getKey());
theField.setType(field.getType());
theField.setValue(this.decipherValue(field));
}
if (fieldFormatting != null){
String format = fieldFormatting.isSet(theField.getKey()) ? fieldFormatting.get(theField.getKey()) : null;
String value = this.format(messageInfo.getUserId(), theField, format);
if (StringUtils.isNullOrEmpty(value)) continue;
text = text.replace(theField.getKey(), value);
result.getReplacedKeys().add(theField.getKey());
}
}
result.setText(text);
return result;
}
protected FieldFormatting buildFieldFormatting(NotificationProperties.Flow.FieldOption options) {
FieldFormatting formatting = new FieldFormatting();
if (options == null || options.getFormatting() == null) return formatting;
for (Map.Entry<String, String> pair : options.getFormatting().entrySet()) {
if (StringUtils.isNullOrEmpty(pair.getValue())) continue;
formatting.put(pair.getKey(), pair.getValue());
}
return formatting;
}
protected FieldFormatting buildFieldFormatting(FieldOptions options) {
FieldFormatting formatting = new FieldFormatting();
if (options == null || options.getFormatting() == null) return formatting;
for (Map.Entry<String, String> pair : options.getFormatting().entrySet()) {
if (StringUtils.isNullOrEmpty(pair.getValue())) continue;
formatting.put(pair.getKey(), pair.getValue());
}
return formatting;
}
protected String lookupOrReadLocalizedFile(NotificationProperties.Template.TemplateCache templateCache, String path, String language) {
String filename = path.replace("{language}", language);
File file = null;
NotificationTemplateCache.NotificationTemplateCacheValue cacheKey =
new NotificationTemplateCache.NotificationTemplateCacheValue(templateCache.getPrefix(),
filename,
templateCache.getKeyPattern());
String content = this.cache.lookup(cacheKey);
if (!StringUtils.isNullOrEmpty(content)) return content;
try {
file = ResourceUtils.getFile(filename);
} catch (FileNotFoundException e) {
throw new MyApplicationException(this.errors.getSystemError().getCode(), this.errors.getSystemError().getMessage());
}
try {
content = new String(new FileInputStream(file).readAllBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
this.cache.put(cacheKey, content);
return content;
}
protected String decipherValue(FieldInfo field) {
try {
return this.cipherService.decryptSymetricAes(field.getValue(), this.cipherProfileProperties.getProfileMap().get("notification-profile-name"));
} catch (Exception ex) {
this.logger.error("could not decipher value " + field.getValue() + " of key " + field.getKey() + ". no value for key", ex);
return null;
}
}
protected ReplaceResult buildTemplate(UUID notificationId, String template, MessageInfo messageInfo, NotificationProperties.Flow.FieldOption options, FieldFormatting formatting, FieldCiphering ciphering) {
ReplaceResult result = this.applyFieldReplace(template, messageInfo, formatting, ciphering);
if (options != null) {
Boolean allMandatory = this.ensureMandatoryFields(result, options.getMandatory() != null ? options.getMandatory() : new ArrayList<>());
if (!allMandatory) {
logger.error("Could not replace all subject mandatory field for notification {}", notificationId);
return null;
}
if (options.getOptional() != null) {
for (FieldInfo field : options.getOptional()) {
result.setText(this.applyFieldReplace(result.getText(), field, "", formatting));
}
}
}
return result;
}
protected ReplaceResult buildTemplate(UUID notificationId, String template, MessageInfo messageInfo, FieldOptions options, FieldFormatting formatting, FieldCiphering ciphering) {
ReplaceResult result = this.applyFieldReplace(template, messageInfo, formatting, ciphering);
if (options != null) {
Boolean allMandatory = this.ensureMandatoryFields(result, options.getMandatory() != null ? options.getMandatory() : new ArrayList<>());
if (!allMandatory) {
logger.error("Could not replace all subject mandatory field for notification {}", notificationId);
return null;
}
if (options.getOptional() != null) {
for (FieldInfo field : options.getOptional()) {
result.setText(this.applyFieldReplace(result.getText(), field, "", formatting));
}
}
}
return result;
}
protected Boolean ensureMandatoryFields(ReplaceResult result, List<String> mandatory) {
for (String field : mandatory) {
if (!result.getReplacedKeys().contains(field)) {
logger.warn("Mandatory field {} was not replaced in message", field);
return false;
}
}
return true;
}
protected String applyFieldReplace(String text, FieldInfo field, String defaultValue, FieldFormatting formatting) {
String txtVal = defaultValue;
if (!StringUtils.isNullOrEmpty(field.getValue())) {
if (formatting.isSet(field.getKey())) txtVal = String.format(formatting.get(field.getKey()), field.getValue());
else txtVal = field.getValue();
}
text = text.replace(field.getKey(), txtVal);
return text;
}
protected String format(UUID userId, FieldInfo field, String format) {
switch (field.getType()) {
case DateTime:
return this.dateTimeFormat(userId, field.getValue(), format);
case Decimal:
return this.decimalFormat(userId, field.getValue(), format);
case Double:
return this.doubleFormat(userId, field.getValue(), format);
case Integer:
return this.integerFormat(userId, field.getValue(), format);
case String:
default:
return this.stringFormat(field.getValue(), format);
}
}
private String stringFormat(String value, String format) {
String val;
if (!StringUtils.isNullOrEmpty(format)) val = String.format(format, value);
else val = value;
return val;
}
private String dateTimeFormat(UUID userId, String value, String format) {
if (StringUtils.isNullOrEmpty(value)) return "";
Instant time = Instant.parse(value);
return formattingService.format(time, userId, null, format, null);
}
private String decimalFormat(UUID userId, String value, String format) {
if (StringUtils.isNullOrEmpty(value)) return "";
Double aDouble = Double.parseDouble(value);
return formattingService.format(aDouble, userId, null, format, null);
}
private String doubleFormat(UUID userId, String value, String format) {
return this.decimalFormat(userId, value, format);
}
private String integerFormat(UUID userId, String value, String format) {
if (StringUtils.isNullOrEmpty(value)) return "";
Integer aInteger = Integer.parseInt(value);
return formattingService.format(aInteger, userId, format, null);
}
}