001package ca.cdr.api.util; 002 003/*- 004 * #%L 005 * Smile CDR - CDR 006 * %% 007 * Copyright (C) 2016 - 2026 Smile CDR, Inc. 008 * %% 009 * All rights reserved. 010 * #L% 011 */ 012 013import ca.cdr.api.model.enm.TransactionLogBodyTypeEnum; 014import ca.cdr.api.model.enm.TransactionLogOutcomeEnum; 015import ca.cdr.api.model.enm.TransactionLogStepTypeEnum; 016import ca.cdr.api.model.json.TransactionLogStepJson; 017import ca.cdr.api.pub.hl7v2.model.MappingMessage; 018import jakarta.annotation.Nullable; 019 020import java.util.Date; 021import java.util.List; 022import java.util.stream.Collectors; 023 024import static org.apache.commons.lang3.StringUtils.isNotBlank; 025 026public class MessageMappingUtil { 027 private MessageMappingUtil() {} 028 029 /** 030 * Given a set of mapping issues (if any), generate a {@link TransactionLogStepJson} 031 * that can be sent to the transaction log service. Will only return 032 * an object if any issues are actually present, otherwise returns null. 033 * 034 * @return Returns null if no issues detected 035 */ 036 @Nullable 037 public static TransactionLogStepJson createTransactionLogStep(List<MappingMessage> theIssues) { 038 if (theIssues.isEmpty()) { 039 return null; 040 } 041 042 TransactionLogStepJson mapStep = new TransactionLogStepJson(); 043 mapStep.setOutcome(hasErrors(theIssues) ? TransactionLogOutcomeEnum.FAIL : TransactionLogOutcomeEnum.SUCCESS); 044 mapStep.setType(TransactionLogStepTypeEnum.PROCESSING); 045 mapStep.setBody(toMarkdown(theIssues)); 046 mapStep.setBodyType(TransactionLogBodyTypeEnum.MESSAGE_MARKDOWN); 047 mapStep.setInitialTimestamp(new Date()); 048 return mapStep; 049 } 050 051 /** 052 * Returns {@code true} if any of the given mapping issues has a level of 053 * {@link MappingMessage.MessageLevel#ERROR ERROR} or higher. 054 */ 055 public static boolean hasErrors(List<MappingMessage> theIssues) { 056 return theIssues.stream().anyMatch(t -> isAtLeastError(t.getLevel())); 057 } 058 059 /** 060 * Returns {@code true} if the given severity level is {@link MappingMessage.MessageLevel#ERROR} or higher. 061 */ 062 public static boolean isAtLeastError(MappingMessage.MessageLevel theLevel) { 063 return theLevel.ordinal() >= MappingMessage.MessageLevel.ERROR.ordinal(); 064 } 065 066 /** 067 * Formats the given mapping issues as a markdown bullet list. 068 */ 069 public static String toMarkdown(List<MappingMessage> theIssues) { 070 StringBuilder messageMarkdown = new StringBuilder(); 071 for (MappingMessage nextIssue : theIssues) { 072 if (!messageMarkdown.isEmpty()) { 073 messageMarkdown.append("\n"); 074 } 075 messageMarkdown.append("* "); 076 messageMarkdown.append("[**").append(nextIssue.getLevel().name()).append("**] "); 077 if (isNotBlank(nextIssue.getPath())) { 078 messageMarkdown.append(" `").append(nextIssue.getPath()).append("` - "); 079 } 080 messageMarkdown.append(nextIssue.getMessage()); 081 } 082 return messageMarkdown.toString(); 083 } 084 085 /** 086 * Formats the given mapping issues as a semicolon-delimited string suitable for log output. 087 * Each issue is formatted as {@code [LEVEL] path - message}. 088 */ 089 public static String toLogMessage(List<MappingMessage> theIssues) { 090 return theIssues.stream() 091 .map(i -> "[" + i.getLevel() + "] " + i.getPath() + " - " + i.getMessage()) 092 .collect(Collectors.joining("; ")); 093 } 094}