001package ca.uhn.fhir.rest.server.messaging;
002
003/*-
004 * #%L
005 * HAPI FHIR - Server Framework
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023
024
025import ca.uhn.fhir.model.api.IModelJson;
026import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
027import com.fasterxml.jackson.annotation.JsonProperty;
028import org.apache.commons.lang3.Validate;
029
030import javax.annotation.Nullable;
031import java.util.HashMap;
032import java.util.Map;
033import java.util.Optional;
034
035@SuppressWarnings("WeakerAccess")
036public abstract class BaseResourceMessage implements IResourceMessage, IModelJson {
037
038        @JsonProperty("operationType")
039        protected BaseResourceModifiedMessage.OperationTypeEnum myOperationType;
040
041        @JsonProperty("attributes")
042        private Map<String, String> myAttributes;
043
044        @JsonProperty("transactionId")
045        private String myTransactionId;
046
047        @JsonProperty("mediaType")
048        private String myMediaType;
049
050        /**
051         * This is used by any message going to kafka for topic partition selection purposes.
052         */
053        @JsonProperty("messageKey")
054        private String myMessageKey;
055
056        /**
057         * Returns an attribute stored in this message.
058         * <p>
059         * Attributes are just a spot for user data of any kind to be
060         * added to the message for pasing along the subscription processing
061         * pipeline (typically by interceptors). Values will be carried from the beginning to the end.
062         * </p>
063         * <p>
064         * Note that messages are designed to be passed into queueing systems
065         * and serialized as JSON. As a result, only strings are currently allowed
066         * as values.
067         * </p>
068         */
069        public Optional<String> getAttribute(String theKey) {
070                Validate.notBlank(theKey);
071                if (myAttributes == null) {
072                        return Optional.empty();
073                }
074                return Optional.ofNullable(myAttributes.get(theKey));
075        }
076
077        /**
078         * Sets an attribute stored in this message.
079         * <p>
080         * Attributes are just a spot for user data of any kind to be
081         * added to the message for passing along the subscription processing
082         * pipeline (typically by interceptors). Values will be carried from the beginning to the end.
083         * </p>
084         * <p>
085         * Note that messages are designed to be passed into queueing systems
086         * and serialized as JSON. As a result, only strings are currently allowed
087         * as values.
088         * </p>
089         *
090         * @param theKey   The key (must not be null or blank)
091         * @param theValue The value (must not be null)
092         */
093        public void setAttribute(String theKey, String theValue) {
094                Validate.notBlank(theKey);
095                Validate.notNull(theValue);
096                if (myAttributes == null) {
097                        myAttributes = new HashMap<>();
098                }
099                myAttributes.put(theKey, theValue);
100        }
101
102        /**
103         * Copies any attributes from the given message into this messsage.
104         *
105         * @see #setAttribute(String, String)
106         * @see #getAttribute(String)
107         */
108        public void copyAdditionalPropertiesFrom(BaseResourceMessage theMsg) {
109                if (theMsg.myAttributes != null) {
110                        if (myAttributes == null) {
111                                myAttributes = new HashMap<>();
112                        }
113                        myAttributes.putAll(theMsg.myAttributes);
114                }
115        }
116
117        /**
118         * Returns the {@link OperationTypeEnum} that is occurring to the Resource of the message
119         *
120         * @return the operation type.
121         */
122        public BaseResourceModifiedMessage.OperationTypeEnum getOperationType() {
123                return myOperationType;
124        }
125
126        /**
127         * Sets the {@link OperationTypeEnum} occuring to the resource of the message.
128         *
129         * @param theOperationType The operation type to set.
130         */
131        public void setOperationType(BaseResourceModifiedMessage.OperationTypeEnum theOperationType) {
132                myOperationType = theOperationType;
133        }
134
135        /**
136         * Retrieve the transaction ID related to this message.
137         *
138         * @return the transaction ID, or null.
139         */
140        @Nullable
141        public String getTransactionId() {
142                return myTransactionId;
143        }
144
145        /**
146         * Adds a transaction ID to this message. This ID can be used for many purposes. For example, performing tracing
147         * across asynchronous hooks, tying data together, or downstream logging purposes.
148         *
149         * One current internal implementation uses this field to tie back MDM processing results (which are asynchronous)
150         * to the original transaction log that caused the MDM processing to occur.
151         *
152         * @param theTransactionId An ID representing a transaction of relevance to this message.
153         */
154        public void setTransactionId(String theTransactionId) {
155                myTransactionId = theTransactionId;
156        }
157
158        public String getMediaType() {
159                return myMediaType;
160        }
161
162        public void setMediaType(String theMediaType) {
163                myMediaType = theMediaType;
164        }
165
166        @Nullable
167        public String getMessageKeyOrNull() {
168                return myMessageKey;
169        }
170
171        public void setMessageKey(String theMessageKey) {
172                myMessageKey = theMessageKey;
173        }
174
175        public enum OperationTypeEnum {
176                CREATE(RestOperationTypeEnum.CREATE),
177                UPDATE(RestOperationTypeEnum.UPDATE),
178                DELETE(RestOperationTypeEnum.DELETE),
179                MANUALLY_TRIGGERED(RestOperationTypeEnum.UPDATE),
180                TRANSACTION(RestOperationTypeEnum.UPDATE);
181
182                private final RestOperationTypeEnum myRestOperationTypeEnum;
183
184                OperationTypeEnum(RestOperationTypeEnum theRestOperationTypeEnum) {
185                        myRestOperationTypeEnum = theRestOperationTypeEnum;
186                }
187
188                public RestOperationTypeEnum asRestOperationType() {
189                        return myRestOperationTypeEnum;
190                }
191        }
192}