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