001/* 002 * #%L 003 * HAPI FHIR JPA Server 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jpa.entity; 021 022import ca.uhn.fhir.util.ValidateUtil; 023import com.google.common.annotations.VisibleForTesting; 024import jakarta.annotation.Nonnull; 025import jakarta.persistence.Column; 026import jakarta.persistence.Entity; 027import jakarta.persistence.FetchType; 028import jakarta.persistence.ForeignKey; 029import jakarta.persistence.GeneratedValue; 030import jakarta.persistence.GenerationType; 031import jakarta.persistence.Id; 032import jakarta.persistence.JoinColumn; 033import jakarta.persistence.Lob; 034import jakarta.persistence.ManyToOne; 035import jakarta.persistence.OneToMany; 036import jakarta.persistence.SequenceGenerator; 037import jakarta.persistence.Table; 038import jakarta.persistence.Transient; 039import jakarta.persistence.UniqueConstraint; 040import org.apache.commons.lang3.builder.EqualsBuilder; 041import org.apache.commons.lang3.builder.HashCodeBuilder; 042import org.apache.commons.lang3.builder.ToStringBuilder; 043import org.apache.commons.lang3.builder.ToStringStyle; 044import org.hibernate.Length; 045 046import java.io.Serializable; 047import java.util.ArrayList; 048import java.util.List; 049 050import static java.util.Objects.nonNull; 051import static org.apache.commons.lang3.StringUtils.isNotEmpty; 052import static org.apache.commons.lang3.StringUtils.left; 053import static org.apache.commons.lang3.StringUtils.length; 054 055/* 056 * DM 2019-08-01 - Do not use IDX_VALUESET_CONCEPT_CS_CD or IDX_VALUESET_CONCEPT_CS_CODE; this was previously used as an index so reusing the name will 057 * bork up migration tasks. 058 */ 059@Table( 060 name = "TRM_VALUESET_CONCEPT", 061 uniqueConstraints = { 062 @UniqueConstraint( 063 name = "IDX_VS_CONCEPT_CSCD", 064 columnNames = {"VALUESET_PID", "SYSTEM_URL", "CODEVAL"}), 065 @UniqueConstraint( 066 name = "IDX_VS_CONCEPT_ORDER", 067 columnNames = {"VALUESET_PID", "VALUESET_ORDER"}) 068 }) 069@Entity() 070public class TermValueSetConcept implements Serializable { 071 private static final long serialVersionUID = 1L; 072 073 @Id() 074 @SequenceGenerator(name = "SEQ_VALUESET_CONCEPT_PID", sequenceName = "SEQ_VALUESET_CONCEPT_PID") 075 @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_VALUESET_CONCEPT_PID") 076 @Column(name = "PID") 077 private Long myId; 078 079 @ManyToOne(fetch = FetchType.LAZY) 080 @JoinColumn( 081 name = "VALUESET_PID", 082 referencedColumnName = "PID", 083 nullable = false, 084 foreignKey = @ForeignKey(name = "FK_TRM_VALUESET_PID")) 085 private TermValueSet myValueSet; 086 087 @Column(name = "VALUESET_PID", insertable = false, updatable = false, nullable = false) 088 private Long myValueSetPid; 089 090 @Column(name = "INDEX_STATUS", nullable = true) 091 private Long myIndexStatus; 092 093 @Column(name = "VALUESET_ORDER", nullable = false) 094 private int myOrder; 095 096 @Transient 097 private String myValueSetUrl; 098 099 @Transient 100 private String myValueSetName; 101 102 @Column(name = "SOURCE_PID", nullable = true) 103 private Long mySourceConceptPid; 104 105 @Deprecated(since = "7.2.0") 106 @Lob 107 @Column(name = "SOURCE_DIRECT_PARENT_PIDS", nullable = true) 108 private String mySourceConceptDirectParentPids; 109 110 @Column(name = "SOURCE_DIRECT_PARENT_PIDS_VC", nullable = true, length = Length.LONG32) 111 private String mySourceConceptDirectParentPidsVc; 112 113 @Column(name = "SYSTEM_URL", nullable = false, length = TermCodeSystem.MAX_URL_LENGTH) 114 private String mySystem; 115 116 @Column(name = "SYSTEM_VER", nullable = true, length = TermCodeSystemVersion.MAX_VERSION_LENGTH) 117 private String mySystemVer; 118 119 @Column(name = "CODEVAL", nullable = false, length = TermConcept.MAX_CODE_LENGTH) 120 private String myCode; 121 122 @Column(name = "DISPLAY", nullable = true, length = TermConcept.MAX_DESC_LENGTH) 123 private String myDisplay; 124 125 @OneToMany(mappedBy = "myConcept", fetch = FetchType.LAZY) 126 private List<TermValueSetConceptDesignation> myDesignations; 127 128 @Transient 129 private transient Integer myHashCode; 130 131 /** 132 * Constructor 133 */ 134 public TermValueSetConcept() { 135 super(); 136 } 137 138 public Long getId() { 139 return myId; 140 } 141 142 public TermValueSet getValueSet() { 143 return myValueSet; 144 } 145 146 public TermValueSetConcept setValueSet(TermValueSet theValueSet) { 147 myValueSet = theValueSet; 148 return this; 149 } 150 151 public int getOrder() { 152 return myOrder; 153 } 154 155 public TermValueSetConcept setOrder(int theOrder) { 156 myOrder = theOrder; 157 return this; 158 } 159 160 public String getValueSetUrl() { 161 if (myValueSetUrl == null) { 162 myValueSetUrl = getValueSet().getUrl(); 163 } 164 165 return myValueSetUrl; 166 } 167 168 public String getValueSetName() { 169 if (myValueSetName == null) { 170 myValueSetName = getValueSet().getName(); 171 } 172 173 return myValueSetName; 174 } 175 176 public String getSystem() { 177 return mySystem; 178 } 179 180 public TermValueSetConcept setSystem(@Nonnull String theSystem) { 181 ValidateUtil.isNotBlankOrThrowIllegalArgument(theSystem, "theSystem must not be null or empty"); 182 ValidateUtil.isNotTooLongOrThrowIllegalArgument( 183 theSystem, 184 TermCodeSystem.MAX_URL_LENGTH, 185 "System exceeds maximum length (" + TermCodeSystem.MAX_URL_LENGTH + "): " + length(theSystem)); 186 mySystem = theSystem; 187 return this; 188 } 189 190 public String getSystemVersion() { 191 return mySystemVer; 192 } 193 194 public TermValueSetConcept setSystemVersion(String theSystemVersion) { 195 ValidateUtil.isNotTooLongOrThrowIllegalArgument( 196 theSystemVersion, 197 TermCodeSystemVersion.MAX_VERSION_LENGTH, 198 "System version exceeds maximum length (" + TermCodeSystemVersion.MAX_VERSION_LENGTH + "): " 199 + length(theSystemVersion)); 200 mySystemVer = theSystemVersion; 201 return this; 202 } 203 204 public String getCode() { 205 return myCode; 206 } 207 208 public TermValueSetConcept setCode(@Nonnull String theCode) { 209 ValidateUtil.isNotBlankOrThrowIllegalArgument(theCode, "theCode must not be null or empty"); 210 ValidateUtil.isNotTooLongOrThrowIllegalArgument( 211 theCode, 212 TermConcept.MAX_CODE_LENGTH, 213 "Code exceeds maximum length (" + TermConcept.MAX_CODE_LENGTH + "): " + length(theCode)); 214 myCode = theCode; 215 return this; 216 } 217 218 public String getDisplay() { 219 return myDisplay; 220 } 221 222 public TermValueSetConcept setDisplay(String theDisplay) { 223 myDisplay = left(theDisplay, TermConcept.MAX_DESC_LENGTH); 224 return this; 225 } 226 227 public List<TermValueSetConceptDesignation> getDesignations() { 228 if (myDesignations == null) { 229 myDesignations = new ArrayList<>(); 230 } 231 232 return myDesignations; 233 } 234 235 @Override 236 public boolean equals(Object theO) { 237 if (this == theO) return true; 238 239 if (!(theO instanceof TermValueSetConcept)) return false; 240 241 TermValueSetConcept that = (TermValueSetConcept) theO; 242 243 return new EqualsBuilder() 244 .append(myValueSetPid, that.myValueSetPid) 245 .append(getSystem(), that.getSystem()) 246 .append(getCode(), that.getCode()) 247 .isEquals(); 248 } 249 250 @Override 251 public int hashCode() { 252 if (myHashCode == null) { 253 myHashCode = new HashCodeBuilder(17, 37) 254 .append(myValueSetPid) 255 .append(getSystem()) 256 .append(getCode()) 257 .toHashCode(); 258 } 259 return myHashCode; 260 } 261 262 @Override 263 public String toString() { 264 return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 265 .append("id", myId) 266 .append("order", myOrder) 267 .append("system", mySystem) 268 .append("code", myCode) 269 .append("valueSet", myValueSet != null ? myValueSet.getId() : "(null)") 270 .append("valueSetPid", myValueSetPid) 271 .append("valueSetUrl", this.getValueSetUrl()) 272 .append("valueSetName", this.getValueSetName()) 273 .append("display", myDisplay) 274 .append("designationCount", myDesignations != null ? myDesignations.size() : "(null)") 275 .append("parentPids", getSourceConceptDirectParentPids()) 276 .toString(); 277 } 278 279 public Long getIndexStatus() { 280 return myIndexStatus; 281 } 282 283 public void setIndexStatus(Long theIndexStatus) { 284 myIndexStatus = theIndexStatus; 285 } 286 287 public void setSourceConceptPid(Long theSourceConceptPid) { 288 mySourceConceptPid = theSourceConceptPid; 289 } 290 291 public void setSourceConceptDirectParentPids(String theSourceConceptDirectParentPids) { 292 mySourceConceptDirectParentPids = theSourceConceptDirectParentPids; 293 mySourceConceptDirectParentPidsVc = theSourceConceptDirectParentPids; 294 } 295 296 public String getSourceConceptDirectParentPids() { 297 return isNotEmpty(mySourceConceptDirectParentPidsVc) 298 ? mySourceConceptDirectParentPidsVc 299 : mySourceConceptDirectParentPids; 300 } 301 302 public void clearSourceConceptDirectParentPidsLob() { 303 mySourceConceptDirectParentPids = null; 304 } 305 306 @VisibleForTesting 307 public boolean hasSourceConceptDirectParentPidsLob() { 308 return nonNull(mySourceConceptDirectParentPids); 309 } 310}