001package ca.uhn.fhir.jpa.subscription.model;
002
003/*-
004 * #%L
005 * HAPI FHIR Storage api
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
023import ca.uhn.fhir.context.FhirContext;
024import ca.uhn.fhir.model.api.IModelJson;
025import com.fasterxml.jackson.annotation.JsonProperty;
026import org.apache.commons.lang3.builder.EqualsBuilder;
027import org.apache.commons.lang3.builder.HashCodeBuilder;
028import org.apache.commons.lang3.builder.ToStringBuilder;
029import org.hl7.fhir.instance.model.api.IIdType;
030import org.hl7.fhir.instance.model.api.IPrimitiveType;
031import org.hl7.fhir.r4.model.IdType;
032import org.hl7.fhir.r4.model.Subscription;
033
034import javax.annotation.Nonnull;
035import javax.annotation.Nullable;
036import java.io.Serializable;
037import java.util.ArrayList;
038import java.util.Collections;
039import java.util.HashMap;
040import java.util.List;
041import java.util.Map;
042
043import static org.apache.commons.lang3.StringUtils.isNotBlank;
044
045public class CanonicalSubscription implements Serializable, Cloneable, IModelJson {
046
047        private static final long serialVersionUID = 1L;
048
049        @JsonProperty("id")
050        private String myIdElement;
051        @JsonProperty("criteria")
052        private String myCriteriaString;
053        @JsonProperty("endpointUrl")
054        private String myEndpointUrl;
055        @JsonProperty("payload")
056        private String myPayloadString;
057        @JsonProperty("headers")
058        private List<String> myHeaders;
059        @JsonProperty("channelType")
060        private CanonicalSubscriptionChannelType myChannelType;
061        @JsonProperty("status")
062        private Subscription.SubscriptionStatus myStatus;
063        @JsonProperty("triggerDefinition")
064        private CanonicalEventDefinition myTrigger;
065        @JsonProperty("emailDetails")
066        private EmailDetails myEmailDetails;
067        @JsonProperty("restHookDetails")
068        private RestHookDetails myRestHookDetails;
069        @JsonProperty("extensions")
070        private Map<String, List<String>> myChannelExtensions;
071        @JsonProperty("tags")
072        private Map<String, String> myTags;
073        @JsonProperty("payloadSearchCriteria")
074        private String myPayloadSearchCriteria;
075        @JsonProperty("partitionId")
076        private Integer myPartitionId;
077        @JsonProperty("crossPartitionEnabled")
078        private boolean myCrossPartitionEnabled;
079        @JsonProperty("sendDeleteMessages")
080        private boolean mySendDeleteMessages;
081
082        /**
083         * Constructor
084         */
085        public CanonicalSubscription() {
086                super();
087        }
088
089        public String getPayloadSearchCriteria() {
090                return myPayloadSearchCriteria;
091        }
092
093        public void setPayloadSearchCriteria(String thePayloadSearchCriteria) {
094                myPayloadSearchCriteria = thePayloadSearchCriteria;
095        }
096
097        /**
098         * For now we're using the R4 TriggerDefinition, but this
099         * may change in the future when things stabilize
100         */
101        public void addTrigger(CanonicalEventDefinition theTrigger) {
102                myTrigger = theTrigger;
103        }
104
105        public CanonicalSubscriptionChannelType getChannelType() {
106                return myChannelType;
107        }
108
109        public void setChannelType(CanonicalSubscriptionChannelType theChannelType) {
110                myChannelType = theChannelType;
111        }
112
113        public String getCriteriaString() {
114                return myCriteriaString;
115        }
116
117        public void setCriteriaString(String theCriteriaString) {
118                myCriteriaString = theCriteriaString;
119        }
120
121        public EmailDetails getEmailDetails() {
122                if (myEmailDetails == null) {
123                        myEmailDetails = new EmailDetails();
124                }
125                return myEmailDetails;
126        }
127
128        public String getEndpointUrl() {
129                return myEndpointUrl;
130        }
131
132        public void setEndpointUrl(String theEndpointUrl) {
133                myEndpointUrl = theEndpointUrl;
134        }
135
136        @Nonnull
137        public List<String> getHeaders() {
138                return myHeaders != null ? Collections.unmodifiableList(myHeaders) : Collections.emptyList();
139        }
140
141        public void setHeaders(List<? extends IPrimitiveType<String>> theHeader) {
142                myHeaders = new ArrayList<>();
143                for (IPrimitiveType<String> next : theHeader) {
144                        if (isNotBlank(next.getValueAsString())) {
145                                myHeaders.add(next.getValueAsString());
146                        }
147                }
148        }
149
150        public Map<String, String> getTags() {
151                return myTags;
152        }
153
154        public void setTags(Map<String, String> theTags) {
155                this.myTags = theTags;
156        }
157
158
159        public void setHeaders(String theHeaders) {
160                myHeaders = new ArrayList<>();
161                if (isNotBlank(theHeaders)) {
162                        myHeaders.add(theHeaders);
163                }
164        }
165
166        public String getChannelExtension(String theUrl) {
167                String retVal = null;
168                List<String> channelExtensions = myChannelExtensions.get(theUrl);
169                if (channelExtensions != null && !channelExtensions.isEmpty()) {
170                        retVal = channelExtensions.get(0);
171                }
172                return retVal;
173        }
174
175        @Nonnull
176        public List<String> getChannelExtensions(String theUrl) {
177                List<String> retVal = myChannelExtensions.get(theUrl);
178                if (retVal == null) {
179                        retVal = Collections.emptyList();
180                } else {
181                        retVal = Collections.unmodifiableList(retVal);
182                }
183                return retVal;
184        }
185
186        public void setChannelExtensions(Map<String, List<String>> theChannelExtensions) {
187                myChannelExtensions = new HashMap<>();
188                for (String url : theChannelExtensions.keySet()) {
189                        List<String> values = theChannelExtensions.get(url);
190                        if (isNotBlank(url) && values != null) {
191                                myChannelExtensions.put(url, values);
192                        }
193                }
194        }
195
196        @Nullable
197        public IIdType getIdElement(FhirContext theContext) {
198                IIdType retVal = null;
199                if (isNotBlank(myIdElement)) {
200                        retVal = theContext.getVersion().newIdType().setValue(myIdElement);
201                }
202                return retVal;
203        }
204
205        public String getIdPart() {
206                return new IdType(getIdElementString()).getIdPart();
207        }
208
209        public String getIdElementString() {
210                return myIdElement;
211        }
212
213        public String getPayloadString() {
214                return myPayloadString;
215        }
216
217        public void setPayloadString(String thePayloadString) {
218                myPayloadString = thePayloadString;
219        }
220
221        public RestHookDetails getRestHookDetails() {
222                if (myRestHookDetails == null) {
223                        myRestHookDetails = new RestHookDetails();
224                }
225                return myRestHookDetails;
226        }
227
228        public Subscription.SubscriptionStatus getStatus() {
229                return myStatus;
230        }
231
232        public void setStatus(Subscription.SubscriptionStatus theStatus) {
233                myStatus = theStatus;
234        }
235
236        public Integer getRequestPartitionId() {
237                return myPartitionId;
238        }
239
240        public void setPartitionId(Integer thePartitionId) {
241                myPartitionId = thePartitionId;
242        }
243
244        public boolean getCrossPartitionEnabled() {
245                return myCrossPartitionEnabled;
246        }
247
248        public void setCrossPartitionEnabled(boolean myCrossPartitionEnabled) {
249                this.myCrossPartitionEnabled = myCrossPartitionEnabled;
250        }
251
252        /**
253         * For now we're using the R4 triggerdefinition, but this
254         * may change in the future when things stabilize
255         */
256        public CanonicalEventDefinition getTrigger() {
257                return myTrigger;
258        }
259
260        public boolean getSendDeleteMessages() {
261                return mySendDeleteMessages;
262        }
263
264        public void setSendDeleteMessages(boolean theSendDeleteMessages) {
265                mySendDeleteMessages = theSendDeleteMessages;
266        }
267
268        @Override
269        public boolean equals(Object theO) {
270                if (this == theO) return true;
271
272                if (theO == null || getClass() != theO.getClass()) return false;
273
274                CanonicalSubscription that = (CanonicalSubscription) theO;
275
276                EqualsBuilder b = new EqualsBuilder();
277                b.append(myIdElement, that.myIdElement);
278                b.append(myCriteriaString, that.myCriteriaString);
279                b.append(myEndpointUrl, that.myEndpointUrl);
280                b.append(myPayloadString, that.myPayloadString);
281                b.append(myHeaders, that.myHeaders);
282                b.append(myChannelType, that.myChannelType);
283                b.append(myStatus, that.myStatus);
284                b.append(myTrigger, that.myTrigger);
285                b.append(myEmailDetails, that.myEmailDetails);
286                b.append(myRestHookDetails, that.myRestHookDetails);
287                b.append(myChannelExtensions, that.myChannelExtensions);
288                return b.isEquals();
289        }
290
291        @Override
292        public int hashCode() {
293                return new HashCodeBuilder(17, 37)
294                        .append(myIdElement)
295                        .append(myCriteriaString)
296                        .append(myEndpointUrl)
297                        .append(myPayloadString)
298                        .append(myHeaders)
299                        .append(myChannelType)
300                        .append(myStatus)
301                        .append(myTrigger)
302                        .append(myEmailDetails)
303                        .append(myRestHookDetails)
304                        .append(myChannelExtensions)
305                        .toHashCode();
306        }
307
308        public void setIdElement(IIdType theIdElement) {
309                myIdElement = null;
310                if (theIdElement != null) {
311                        myIdElement = theIdElement.toUnqualifiedVersionless().getValue();
312                }
313        }
314
315        /**
316         * Adds a header
317         *
318         * @param theHeader The header, e.g. "Authorization: Bearer AAAAA"
319         */
320        public void addHeader(String theHeader) {
321                if (isNotBlank(theHeader)) {
322                        initHeaders();
323                        myHeaders.add(theHeader);
324                }
325        }
326
327        private void initHeaders() {
328                if (myHeaders == null) {
329                        myHeaders = new ArrayList<>();
330                }
331        }
332
333        @Override
334        public String toString() {
335                return new ToStringBuilder(this)
336                        .append("myIdElement", myIdElement)
337                        .append("myStatus", myStatus)
338                        .append("myCriteriaString", myCriteriaString)
339                        .append("myEndpointUrl", myEndpointUrl)
340                        .append("myPayloadString", myPayloadString)
341//                      .append("myHeaders", myHeaders)
342                        .append("myChannelType", myChannelType)
343//                      .append("myTrigger", myTrigger)
344//                      .append("myEmailDetails", myEmailDetails)
345//                      .append("myRestHookDetails", myRestHookDetails)
346//                      .append("myChannelExtensions", myChannelExtensions)
347                        .toString();
348        }
349
350        public static class EmailDetails implements IModelJson {
351
352                @JsonProperty("from")
353                private String myFrom;
354                @JsonProperty("subjectTemplate")
355                private String mySubjectTemplate;
356
357                /**
358                 * Constructor
359                 */
360                public EmailDetails() {
361                        super();
362                }
363
364                public String getFrom() {
365                        return myFrom;
366                }
367
368                public void setFrom(String theFrom) {
369                        myFrom = theFrom;
370                }
371
372                public String getSubjectTemplate() {
373                        return mySubjectTemplate;
374                }
375
376                public void setSubjectTemplate(String theSubjectTemplate) {
377                        mySubjectTemplate = theSubjectTemplate;
378                }
379
380                @Override
381                public boolean equals(Object theO) {
382                        if (this == theO) return true;
383
384                        if (theO == null || getClass() != theO.getClass()) return false;
385
386                        EmailDetails that = (EmailDetails) theO;
387
388                        return new EqualsBuilder()
389                                .append(myFrom, that.myFrom)
390                                .append(mySubjectTemplate, that.mySubjectTemplate)
391                                .isEquals();
392                }
393
394                @Override
395                public int hashCode() {
396                        return new HashCodeBuilder(17, 37)
397                                .append(myFrom)
398                                .append(mySubjectTemplate)
399                                .toHashCode();
400                }
401        }
402
403        public static class RestHookDetails implements IModelJson {
404
405                @JsonProperty("stripVersionId")
406                private boolean myStripVersionId;
407                @JsonProperty("deliverLatestVersion")
408                private boolean myDeliverLatestVersion;
409
410                /**
411                 * Constructor
412                 */
413                public RestHookDetails() {
414                        super();
415                }
416
417                public boolean isDeliverLatestVersion() {
418                        return myDeliverLatestVersion;
419                }
420
421                public void setDeliverLatestVersion(boolean theDeliverLatestVersion) {
422                        myDeliverLatestVersion = theDeliverLatestVersion;
423                }
424
425
426                public boolean isStripVersionId() {
427                        return myStripVersionId;
428                }
429
430                public void setStripVersionId(boolean theStripVersionId) {
431                        myStripVersionId = theStripVersionId;
432                }
433
434                @Override
435                public boolean equals(Object theO) {
436                        if (this == theO) return true;
437
438                        if (theO == null || getClass() != theO.getClass()) return false;
439
440                        RestHookDetails that = (RestHookDetails) theO;
441
442                        return new EqualsBuilder()
443                                .append(myStripVersionId, that.myStripVersionId)
444                                .append(myDeliverLatestVersion, that.myDeliverLatestVersion)
445                                .isEquals();
446                }
447
448                @Override
449                public int hashCode() {
450                        return new HashCodeBuilder(17, 37)
451                                .append(myStripVersionId)
452                                .append(myDeliverLatestVersion)
453                                .toHashCode();
454                }
455
456        }
457
458        public static class CanonicalEventDefinition implements IModelJson {
459
460                /**
461                 * Constructor
462                 */
463                public CanonicalEventDefinition() {
464                        // nothing yet
465                }
466
467        }
468}