001/*-
002 * #%L
003 * Smile CDR - CDR
004 * %%
005 * Copyright (C) 2016 - 2024 Smile CDR, Inc.
006 * %%
007 * All rights reserved.
008 * #L%
009 */
010package ca.cdr.api.util;
011
012import ca.cdr.api.model.json.TransactionLogStepJson;
013import ca.cdr.api.pub.hl7v2.model.MappingMessage;
014import ca.uhn.fhir.rest.api.server.RequestDetails;
015import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
016import com.fasterxml.jackson.core.JsonProcessingException;
017import com.fasterxml.jackson.databind.ObjectMapper;
018import jakarta.annotation.Nullable;
019import org.apache.commons.lang3.Validate;
020
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import static java.util.Objects.isNull;
028
029public class TransactionLogRequestDetailsAccess {
030        private static final org.slf4j.Logger ourLog =
031                        org.slf4j.LoggerFactory.getLogger(TransactionLogRequestDetailsAccess.class);
032        public static final String STEPS_LIST_KEY = TransactionLogRequestDetailsAccess.class.getName() + "_STEPS_LIST";
033        public static final String REQUEST_SUBTYPE_KEY =
034                        TransactionLogRequestDetailsAccess.class.getName() + "_REQUEST_SUBTYPE_KEY";
035        private static final String MESSAGES_LIST_KEY = TransactionLogRequestDetailsAccess.class.getName() + "_STEPS_LIST";
036        private static final String ADDITIONAL_JSON_MAP_KEY =
037                        TransactionLogRequestDetailsAccess.class.getName() + "_ADDITIONAL_JSON_MAP";
038
039        private static final ObjectMapper ourObjectMapper = new ObjectMapper();
040
041        public static void addMessageToRequest(RequestDetails theDetails, MappingMessage theMessage) {
042                Validate.notNull(theDetails, "theDetails must not be null");
043                Validate.notNull(theMessage, "theMessage must not be null");
044                @SuppressWarnings("unchecked")
045                List<MappingMessage> messages =
046                                (List<MappingMessage>) theDetails.getUserData().get(MESSAGES_LIST_KEY);
047                if (messages == null) {
048                        messages = new ArrayList<>();
049                        theDetails.getUserData().put(MESSAGES_LIST_KEY, messages);
050                }
051                messages.add(theMessage);
052        }
053
054        @SuppressWarnings("unchecked")
055        public static List<MappingMessage> getMessagesOnRequest(RequestDetails theDetails) {
056                List<MappingMessage> messages =
057                                (List<MappingMessage>) theDetails.getUserData().get(MESSAGES_LIST_KEY);
058                if (messages == null) {
059                        return Collections.emptyList();
060                }
061                return Collections.unmodifiableList(messages);
062        }
063
064        @SuppressWarnings("unchecked")
065        public static @Nullable List<TransactionLogStepJson> getTransactionLogStepsFromRequest(
066                        ServletRequestDetails theRequestDetails) {
067                if (theRequestDetails == null) {
068                        return null;
069                }
070
071                return (List<TransactionLogStepJson>)
072                                theRequestDetails.getServletRequest().getAttribute(TransactionLogRequestDetailsAccess.STEPS_LIST_KEY);
073        }
074
075        /**
076         * Utility method to add key/value pairs to a transactionLog.  The provided value object needs to be serializable
077         * with Jackson since pairs are accumulated and subsequently formatted in an inline Json string.
078         *
079         * IllegalArgumentException is thrown if <code>theObject</code> is not Json serializable with Jackson or <code>null</code>.
080         *
081         * @param theRequestDetails The request details where the pairs will be stored
082         * @param theKey The key for referencing to theObject.  Keys are transformed into json properties when serializing a pair.
083         * @param theObject The value needing storage.  Values are transformed into json values when serializing a pair.
084         *
085         */
086        public static void addAdditionalJsonProperty(RequestDetails theRequestDetails, String theKey, Object theObject) {
087                Validate.notNull(theRequestDetails, "theDetails must not be null");
088                Validate.notNull(theKey, "theKey must not be null");
089                Validate.notNull(theObject, "theObject must not be null");
090
091                try {
092                        ourObjectMapper.writeValueAsString(theObject);
093                } catch (JsonProcessingException e) {
094                        throw new IllegalArgumentException(
095                                        String.format(
096                                                        "Unable to add pair with key %s to the additional Json property as the provided value object could not be parsed.",
097                                                        theKey),
098                                        e);
099                }
100
101                Map<String, Object> additionalJsonPropertiesMap = getAdditionalJsonPropertiesMap(theRequestDetails);
102
103                additionalJsonPropertiesMap.put(theKey, theObject);
104        }
105
106        public static Map<String, Object> getAdditionalJsonPropertiesMap(RequestDetails theRequestDetails) {
107                Validate.notNull(theRequestDetails, "theDetails must not be null");
108
109                @SuppressWarnings("unchecked")
110                Map<String, Object> additionalJsonPropertiesMap =
111                                (Map<String, Object>) theRequestDetails.getAttribute(ADDITIONAL_JSON_MAP_KEY);
112
113                if (isNull(additionalJsonPropertiesMap)) {
114                        additionalJsonPropertiesMap = new HashMap<>();
115                        theRequestDetails.setAttribute(ADDITIONAL_JSON_MAP_KEY, additionalJsonPropertiesMap);
116                }
117
118                return additionalJsonPropertiesMap;
119        }
120}