001/*-
002 * #%L
003 * HAPI FHIR Storage api
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.jpa.subscription.model;
021
022import ca.uhn.fhir.context.FhirContext;
023import ca.uhn.fhir.interceptor.model.RequestPartitionId;
024import ca.uhn.fhir.parser.IParser;
025import ca.uhn.fhir.rest.api.EncodingEnum;
026import ca.uhn.fhir.rest.server.messaging.BaseResourceMessage;
027import ca.uhn.fhir.rest.server.messaging.IResourceMessage;
028import com.fasterxml.jackson.annotation.JsonIgnore;
029import com.fasterxml.jackson.annotation.JsonProperty;
030import jakarta.annotation.Nullable;
031import org.apache.commons.lang3.StringUtils;
032import org.apache.commons.lang3.builder.ToStringBuilder;
033import org.hl7.fhir.instance.model.api.IBaseResource;
034import org.hl7.fhir.instance.model.api.IIdType;
035
036import static org.apache.commons.lang3.StringUtils.isNotBlank;
037
038@SuppressWarnings("WeakerAccess")
039public class ResourceDeliveryMessage extends BaseResourceMessage implements IResourceMessage {
040
041        @JsonProperty("canonicalSubscription")
042        private CanonicalSubscription mySubscription;
043
044        @JsonProperty("partitionId")
045        private RequestPartitionId myPartitionId;
046
047        @JsonProperty("payload")
048        private String myPayloadString;
049
050        @JsonProperty("payloadId")
051        private String myPayloadId;
052
053        @JsonIgnore
054        private transient IBaseResource myPayloadDecoded;
055
056        /**
057         * Constructor
058         */
059        public ResourceDeliveryMessage() {
060                super();
061                myPartitionId = RequestPartitionId.defaultPartition();
062        }
063
064        public IBaseResource getPayload(FhirContext theCtx) {
065                IBaseResource retVal = myPayloadDecoded;
066                if (retVal == null && isNotBlank(myPayloadString)) {
067                        IParser parser = EncodingEnum.detectEncoding(myPayloadString).newParser(theCtx);
068                        retVal = parser.parseResource(myPayloadString);
069                        myPayloadDecoded = retVal;
070                }
071                return retVal;
072        }
073
074        public String getPayloadString() {
075                if (this.myPayloadString != null) {
076                        return this.myPayloadString;
077                }
078
079                return "";
080        }
081
082        public IIdType getPayloadId(FhirContext theCtx) {
083                IIdType retVal = null;
084                if (myPayloadId != null) {
085                        retVal = theCtx.getVersion().newIdType().setValue(myPayloadId);
086                }
087                return retVal;
088        }
089
090        public CanonicalSubscription getSubscription() {
091                return mySubscription;
092        }
093
094        public void setSubscription(CanonicalSubscription theSubscription) {
095                mySubscription = theSubscription;
096        }
097
098        public void setPayload(FhirContext theCtx, IBaseResource thePayload, EncodingEnum theEncoding) {
099                /*
100                 * Note that we populate the raw string but don't keep the parsed resource around when we set this. This
101                 * has two reasons:
102                 *  - If we build up a big queue of these on an in-memory queue, we aren't taking up double the memory
103                 *  - If use a serializing queue, we aren't behaving differently (and therefore possibly missing things
104                 *    in tests)
105                 */
106                myPayloadString = theEncoding.newParser(theCtx).encodeResourceToString(thePayload);
107                myPayloadId = thePayload.getIdElement().toUnqualifiedVersionless().getValue();
108        }
109
110        public void setPayloadToNull() {
111                myPayloadString = null;
112        }
113
114        @Override
115        public String getPayloadId() {
116                return myPayloadId;
117        }
118
119        public void setPayloadId(IIdType thePayloadId) {
120                myPayloadId = null;
121                if (thePayloadId != null) {
122                        myPayloadId = thePayloadId.getValue();
123                }
124        }
125
126        public RequestPartitionId getRequestPartitionId() {
127                return myPartitionId;
128        }
129
130        public void setPartitionId(RequestPartitionId thePartitionId) {
131                myPartitionId = thePartitionId;
132        }
133
134        @Override
135        public String toString() {
136                return new ToStringBuilder(this)
137                                .append("mySubscription", mySubscription == null ? "null" : mySubscription.getIdElementString())
138                                // it isn't safe to log payloads
139                                .append("myPayloadString", "[Not Logged]")
140                                .append("myPayload", myPayloadDecoded)
141                                .append("myPayloadId", myPayloadId)
142                                .append("myPartitionId", myPartitionId)
143                                .append("myOperationType", getOperationType())
144                                .toString();
145        }
146
147        /**
148         * Helper method to fetch the subscription ID
149         */
150        public String getSubscriptionId(FhirContext theFhirContext) {
151                String retVal = null;
152                if (getSubscription() != null) {
153                        IIdType idElement = getSubscription().getIdElement(theFhirContext);
154                        if (idElement != null) {
155                                retVal = idElement.getValue();
156                        }
157                }
158                return retVal;
159        }
160
161        @Nullable
162        @Override
163        public String getMessageKeyOrDefault() {
164                return StringUtils.defaultString(super.getMessageKeyOrNull(), myPayloadId);
165        }
166}