
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}