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}