001package ca.uhn.fhir.jpa.subscription.model;
002
003/*-
004 * #%L
005 * HAPI FHIR Subscription Server
006 * %%
007 * Copyright (C) 2014 - 2021 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("payloadSearchCriteria")
072        private String myPayloadSearchCriteria;
073
074        /**
075         * Constructor
076         */
077        public CanonicalSubscription() {
078                super();
079        }
080
081        public String getPayloadSearchCriteria() {
082                return myPayloadSearchCriteria;
083        }
084
085        public void setPayloadSearchCriteria(String thePayloadSearchCriteria) {
086                myPayloadSearchCriteria = thePayloadSearchCriteria;
087        }
088
089        /**
090         * For now we're using the R4 TriggerDefinition, but this
091         * may change in the future when things stabilize
092         */
093        public void addTrigger(CanonicalEventDefinition theTrigger) {
094                myTrigger = theTrigger;
095        }
096
097        public CanonicalSubscriptionChannelType getChannelType() {
098                return myChannelType;
099        }
100
101        public void setChannelType(CanonicalSubscriptionChannelType theChannelType) {
102                myChannelType = theChannelType;
103        }
104
105        public String getCriteriaString() {
106                return myCriteriaString;
107        }
108
109        public void setCriteriaString(String theCriteriaString) {
110                myCriteriaString = theCriteriaString;
111        }
112
113        public EmailDetails getEmailDetails() {
114                if (myEmailDetails == null) {
115                        myEmailDetails = new EmailDetails();
116                }
117                return myEmailDetails;
118        }
119
120        public String getEndpointUrl() {
121                return myEndpointUrl;
122        }
123
124        public void setEndpointUrl(String theEndpointUrl) {
125                myEndpointUrl = theEndpointUrl;
126        }
127
128        @Nonnull
129        public List<String> getHeaders() {
130                return myHeaders != null ? Collections.unmodifiableList(myHeaders) : Collections.emptyList();
131        }
132
133        public void setHeaders(List<? extends IPrimitiveType<String>> theHeader) {
134                myHeaders = new ArrayList<>();
135                for (IPrimitiveType<String> next : theHeader) {
136                        if (isNotBlank(next.getValueAsString())) {
137                                myHeaders.add(next.getValueAsString());
138                        }
139                }
140        }
141
142        public void setHeaders(String theHeaders) {
143                myHeaders = new ArrayList<>();
144                if (isNotBlank(theHeaders)) {
145                        myHeaders.add(theHeaders);
146                }
147        }
148
149        public String getChannelExtension(String theUrl) {
150                String retVal = null;
151                List<String> strings = myChannelExtensions.get(theUrl);
152                if (strings != null && strings.isEmpty() == false) {
153                        retVal = strings.get(0);
154                }
155                return retVal;
156        }
157
158        @Nonnull
159        public List<String> getChannelExtensions(String theUrl) {
160                List<String> retVal = myChannelExtensions.get(theUrl);
161                if (retVal == null) {
162                        retVal = Collections.emptyList();
163                } else {
164                        retVal = Collections.unmodifiableList(retVal);
165                }
166                return retVal;
167        }
168
169        public void setChannelExtensions(Map<String, List<String>> theChannelExtensions) {
170                myChannelExtensions = new HashMap<>();
171                for (String url : theChannelExtensions.keySet()) {
172                        List<String> values = theChannelExtensions.get(url);
173                        if (isNotBlank(url) && values != null) {
174                                myChannelExtensions.put(url, values);
175                        }
176                }
177        }
178
179        @Nullable
180        public IIdType getIdElement(FhirContext theContext) {
181                IIdType retVal = null;
182                if (isNotBlank(myIdElement)) {
183                        retVal = theContext.getVersion().newIdType().setValue(myIdElement);
184                }
185                return retVal;
186        }
187
188        public String getIdPart() {
189                return new IdType(getIdElementString()).getIdPart();
190        }
191
192        public String getIdElementString() {
193                return myIdElement;
194        }
195
196        public String getPayloadString() {
197                return myPayloadString;
198        }
199
200        public void setPayloadString(String thePayloadString) {
201                myPayloadString = thePayloadString;
202        }
203
204        public RestHookDetails getRestHookDetails() {
205                if (myRestHookDetails == null) {
206                        myRestHookDetails = new RestHookDetails();
207                }
208                return myRestHookDetails;
209        }
210
211        public Subscription.SubscriptionStatus getStatus() {
212                return myStatus;
213        }
214
215        public void setStatus(Subscription.SubscriptionStatus theStatus) {
216                myStatus = theStatus;
217        }
218
219        /**
220         * For now we're using the R4 triggerdefinition, but this
221         * may change in the future when things stabilize
222         */
223        public CanonicalEventDefinition getTrigger() {
224                return myTrigger;
225        }
226
227        @Override
228        public boolean equals(Object theO) {
229                if (this == theO) return true;
230
231                if (theO == null || getClass() != theO.getClass()) return false;
232
233                CanonicalSubscription that = (CanonicalSubscription) theO;
234
235                EqualsBuilder b = new EqualsBuilder();
236                b.append(myIdElement, that.myIdElement);
237                b.append(myCriteriaString, that.myCriteriaString);
238                b.append(myEndpointUrl, that.myEndpointUrl);
239                b.append(myPayloadString, that.myPayloadString);
240                b.append(myHeaders, that.myHeaders);
241                b.append(myChannelType, that.myChannelType);
242                b.append(myStatus, that.myStatus);
243                b.append(myTrigger, that.myTrigger);
244                b.append(myEmailDetails, that.myEmailDetails);
245                b.append(myRestHookDetails, that.myRestHookDetails);
246                b.append(myChannelExtensions, that.myChannelExtensions);
247                return b.isEquals();
248        }
249
250        @Override
251        public int hashCode() {
252                return new HashCodeBuilder(17, 37)
253                        .append(myIdElement)
254                        .append(myCriteriaString)
255                        .append(myEndpointUrl)
256                        .append(myPayloadString)
257                        .append(myHeaders)
258                        .append(myChannelType)
259                        .append(myStatus)
260                        .append(myTrigger)
261                        .append(myEmailDetails)
262                        .append(myRestHookDetails)
263                        .append(myChannelExtensions)
264                        .toHashCode();
265        }
266
267        public void setIdElement(IIdType theIdElement) {
268                myIdElement = null;
269                if (theIdElement != null) {
270                        myIdElement = theIdElement.toUnqualifiedVersionless().getValue();
271                }
272        }
273
274        /**
275         * Adds a header
276         *
277         * @param theHeader The header, e.g. "Authorization: Bearer AAAAA"
278         */
279        public void addHeader(String theHeader) {
280                if (isNotBlank(theHeader)) {
281                        initHeaders();
282                        myHeaders.add(theHeader);
283                }
284        }
285
286        private void initHeaders() {
287                if (myHeaders == null) {
288                        myHeaders = new ArrayList<>();
289                }
290        }
291
292        @Override
293        public String toString() {
294                return new ToStringBuilder(this)
295                        .append("myIdElement", myIdElement)
296                        .append("myStatus", myStatus)
297                        .append("myCriteriaString", myCriteriaString)
298                        .append("myEndpointUrl", myEndpointUrl)
299                        .append("myPayloadString", myPayloadString)
300//                      .append("myHeaders", myHeaders)
301                        .append("myChannelType", myChannelType)
302//                      .append("myTrigger", myTrigger)
303//                      .append("myEmailDetails", myEmailDetails)
304//                      .append("myRestHookDetails", myRestHookDetails)
305//                      .append("myChannelExtensions", myChannelExtensions)
306                        .toString();
307        }
308
309        public static class EmailDetails implements IModelJson {
310
311                @JsonProperty("from")
312                private String myFrom;
313                @JsonProperty("subjectTemplate")
314                private String mySubjectTemplate;
315
316                /**
317                 * Construcor
318                 */
319                public EmailDetails() {
320                        super();
321                }
322
323                public String getFrom() {
324                        return myFrom;
325                }
326
327                public void setFrom(String theFrom) {
328                        myFrom = theFrom;
329                }
330
331                public String getSubjectTemplate() {
332                        return mySubjectTemplate;
333                }
334
335                public void setSubjectTemplate(String theSubjectTemplate) {
336                        mySubjectTemplate = theSubjectTemplate;
337                }
338
339                @Override
340                public boolean equals(Object theO) {
341                        if (this == theO) return true;
342
343                        if (theO == null || getClass() != theO.getClass()) return false;
344
345                        EmailDetails that = (EmailDetails) theO;
346
347                        return new EqualsBuilder()
348                                .append(myFrom, that.myFrom)
349                                .append(mySubjectTemplate, that.mySubjectTemplate)
350                                .isEquals();
351                }
352
353                @Override
354                public int hashCode() {
355                        return new HashCodeBuilder(17, 37)
356                                .append(myFrom)
357                                .append(mySubjectTemplate)
358                                .toHashCode();
359                }
360        }
361
362        public static class RestHookDetails implements IModelJson {
363
364                @JsonProperty("stripVersionId")
365                private boolean myStripVersionId;
366                @JsonProperty("deliverLatestVersion")
367                private boolean myDeliverLatestVersion;
368
369                /**
370                 * Constructor
371                 */
372                public RestHookDetails() {
373                        super();
374                }
375
376                public boolean isDeliverLatestVersion() {
377                        return myDeliverLatestVersion;
378                }
379
380                public void setDeliverLatestVersion(boolean theDeliverLatestVersion) {
381                        myDeliverLatestVersion = theDeliverLatestVersion;
382                }
383
384
385                public boolean isStripVersionId() {
386                        return myStripVersionId;
387                }
388
389                public void setStripVersionId(boolean theStripVersionId) {
390                        myStripVersionId = theStripVersionId;
391                }
392
393                @Override
394                public boolean equals(Object theO) {
395                        if (this == theO) return true;
396
397                        if (theO == null || getClass() != theO.getClass()) return false;
398
399                        RestHookDetails that = (RestHookDetails) theO;
400
401                        return new EqualsBuilder()
402                                .append(myStripVersionId, that.myStripVersionId)
403                                .append(myDeliverLatestVersion, that.myDeliverLatestVersion)
404                                .isEquals();
405                }
406
407                @Override
408                public int hashCode() {
409                        return new HashCodeBuilder(17, 37)
410                                .append(myStripVersionId)
411                                .append(myDeliverLatestVersion)
412                                .toHashCode();
413                }
414
415        }
416
417        public static class CanonicalEventDefinition implements IModelJson {
418
419                /**
420                 * Constructor
421                 */
422                public CanonicalEventDefinition() {
423                        // nothing yet
424                }
425
426        }
427}