001/* 002 * #%L 003 * HAPI FHIR JPA Server 004 * %% 005 * Copyright (C) 2014 - 2025 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.jpa.model.entity.BasePartitionable; 023import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId; 024import ca.uhn.fhir.jpa.model.entity.ResourceTable; 025import ca.uhn.fhir.util.ValidateUtil; 026import jakarta.annotation.Nonnull; 027import jakarta.annotation.Nullable; 028import jakarta.persistence.Column; 029import jakarta.persistence.Entity; 030import jakarta.persistence.FetchType; 031import jakarta.persistence.ForeignKey; 032import jakarta.persistence.GeneratedValue; 033import jakarta.persistence.GenerationType; 034import jakarta.persistence.Id; 035import jakarta.persistence.IdClass; 036import jakarta.persistence.Index; 037import jakarta.persistence.JoinColumn; 038import jakarta.persistence.JoinColumns; 039import jakarta.persistence.ManyToOne; 040import jakarta.persistence.OneToMany; 041import jakarta.persistence.SequenceGenerator; 042import jakarta.persistence.Table; 043import jakarta.persistence.UniqueConstraint; 044import org.apache.commons.lang3.builder.EqualsBuilder; 045import org.apache.commons.lang3.builder.HashCodeBuilder; 046import org.apache.commons.lang3.builder.ToStringBuilder; 047import org.apache.commons.lang3.builder.ToStringStyle; 048 049import java.io.Serializable; 050import java.util.ArrayList; 051import java.util.Collection; 052 053import static org.apache.commons.lang3.StringUtils.length; 054 055@Table( 056 name = "TRM_CODESYSTEM_VER", 057 // Note, we used to have a constraint named IDX_CSV_RESOURCEPID_AND_VER (don't reuse this) 058 uniqueConstraints = { 059 @UniqueConstraint( 060 name = TermCodeSystemVersion.IDX_CODESYSTEM_AND_VER, 061 columnNames = {"PARTITION_ID", "CODESYSTEM_PID", "CS_VERSION_ID"}) 062 }, 063 indexes = { 064 @Index(name = "FK_CODESYSVER_RES_ID", columnList = "RES_ID"), 065 @Index(name = "FK_CODESYSVER_CS_ID", columnList = "CODESYSTEM_PID") 066 }) 067@Entity() 068@IdClass(IdAndPartitionId.class) 069public class TermCodeSystemVersion extends BasePartitionable implements Serializable { 070 public static final String IDX_CODESYSTEM_AND_VER = "IDX_CODESYSTEM_AND_VER"; 071 public static final int MAX_VERSION_LENGTH = 200; 072 private static final long serialVersionUID = 1L; 073 074 @OneToMany(fetch = FetchType.LAZY, mappedBy = "myCodeSystem") 075 private Collection<TermConcept> myConcepts; 076 077 @Id 078 @SequenceGenerator(name = "SEQ_CODESYSTEMVER_PID", sequenceName = "SEQ_CODESYSTEMVER_PID") 079 @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CODESYSTEMVER_PID") 080 @Column(name = "PID") 081 private Long myId; 082 083 @ManyToOne(fetch = FetchType.LAZY) 084 @JoinColumns( 085 value = { 086 @JoinColumn( 087 name = "RES_ID", 088 referencedColumnName = "RES_ID", 089 nullable = false, 090 insertable = false, 091 updatable = false), 092 @JoinColumn( 093 name = "PARTITION_ID", 094 referencedColumnName = "PARTITION_ID", 095 nullable = false, 096 insertable = false, 097 updatable = false) 098 }, 099 foreignKey = @ForeignKey(name = "FK_CODESYSVER_RES_ID")) 100 private ResourceTable myResource; 101 102 @Column(name = "RES_ID", nullable = false) 103 private Long myResourcePid; 104 105 @Column(name = "CS_VERSION_ID", nullable = true, updatable = true, length = MAX_VERSION_LENGTH) 106 private String myCodeSystemVersionId; 107 108 /** 109 * This was added in HAPI FHIR 3.3.0 and is nullable just to avoid migration 110 * issued. It should be made non-nullable at some point. 111 */ 112 @ManyToOne(fetch = FetchType.LAZY) 113 @JoinColumns( 114 value = { 115 @JoinColumn( 116 name = "CODESYSTEM_PID", 117 referencedColumnName = "PID", 118 insertable = false, 119 updatable = false, 120 nullable = true), 121 @JoinColumn( 122 name = "PARTITION_ID", 123 referencedColumnName = "PARTITION_ID", 124 insertable = false, 125 nullable = true, 126 updatable = false) 127 }, 128 foreignKey = @ForeignKey(name = "FK_CODESYSVER_CS_ID")) 129 private TermCodeSystem myCodeSystem; 130 131 @Column(name = "CODESYSTEM_PID", insertable = true, updatable = true, nullable = true) 132 private Long myCodeSystemPid; 133 134 @Column(name = "CS_DISPLAY", nullable = true, updatable = true, length = MAX_VERSION_LENGTH) 135 private String myCodeSystemDisplayName; 136 137 /** 138 * Constructor 139 */ 140 public TermCodeSystemVersion() { 141 super(); 142 } 143 144 public TermCodeSystem getCodeSystem() { 145 return myCodeSystem; 146 } 147 148 public TermCodeSystemVersion setCodeSystem(TermCodeSystem theCodeSystem) { 149 myCodeSystem = theCodeSystem; 150 myCodeSystemPid = theCodeSystem.getPid(); 151 assert myCodeSystemPid != null; 152 return this; 153 } 154 155 public String getCodeSystemVersionId() { 156 return myCodeSystemVersionId; 157 } 158 159 public TermCodeSystemVersion setCodeSystemVersionId(String theCodeSystemVersionId) { 160 ValidateUtil.isNotTooLongOrThrowIllegalArgument( 161 theCodeSystemVersionId, 162 MAX_VERSION_LENGTH, 163 "Version ID exceeds maximum length (" + MAX_VERSION_LENGTH + "): " + length(theCodeSystemVersionId)); 164 myCodeSystemVersionId = theCodeSystemVersionId; 165 return this; 166 } 167 168 public Collection<TermConcept> getConcepts() { 169 if (myConcepts == null) { 170 myConcepts = new ArrayList<>(); 171 } 172 return myConcepts; 173 } 174 175 @Nullable 176 public Long getPid() { 177 return myId; 178 } 179 180 @Nonnull 181 public IdAndPartitionId getId() { 182 return IdAndPartitionId.forId(myId, this); 183 } 184 185 public ResourceTable getResource() { 186 return myResource; 187 } 188 189 public TermCodeSystemVersion setResource(ResourceTable theResource) { 190 myResource = theResource; 191 myResourcePid = theResource.getId().getId(); 192 setPartitionId(theResource.getPartitionId()); 193 return this; 194 } 195 196 public TermCodeSystemVersion setId(Long theId) { 197 myId = theId; 198 return this; 199 } 200 201 @Override 202 public boolean equals(Object theO) { 203 if (this == theO) { 204 return true; 205 } 206 207 if (theO == null || getClass() != theO.getClass()) { 208 return false; 209 } 210 211 TermCodeSystemVersion that = (TermCodeSystemVersion) theO; 212 213 return new EqualsBuilder() 214 .append(myCodeSystemVersionId, that.myCodeSystemVersionId) 215 .append(myCodeSystemPid, that.myCodeSystemPid) 216 .isEquals(); 217 } 218 219 @Override 220 public int hashCode() { 221 HashCodeBuilder b = new HashCodeBuilder(17, 37); 222 b.append(myCodeSystemVersionId); 223 b.append(myCodeSystemPid); 224 return b.toHashCode(); 225 } 226 227 public String getCodeSystemDisplayName() { 228 return myCodeSystemDisplayName; 229 } 230 231 public void setCodeSystemDisplayName(String theCodeSystemDisplayName) { 232 ValidateUtil.isNotTooLongOrThrowIllegalArgument( 233 theCodeSystemDisplayName, 234 MAX_VERSION_LENGTH, 235 "Version ID exceeds maximum length (" + MAX_VERSION_LENGTH + "): " + length(theCodeSystemDisplayName)); 236 myCodeSystemDisplayName = theCodeSystemDisplayName; 237 } 238 239 public TermConcept addConcept() { 240 TermConcept concept = new TermConcept(); 241 concept.setCodeSystemVersion(this); 242 getConcepts().add(concept); 243 return concept; 244 } 245 246 @Override 247 public String toString() { 248 ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); 249 b.append("pid", myId); 250 b.append("displayName", myCodeSystemDisplayName); 251 b.append("codeSystemResourcePid", myResourcePid); 252 b.append("codeSystemPid", myCodeSystemPid); 253 b.append("codeSystemVersionId", myCodeSystemVersionId); 254 return b.toString(); 255 } 256 257 TermCodeSystemVersion setCodeSystemPidForUnitTest(long theCodeSystemPid) { 258 myCodeSystemPid = theCodeSystemPid; 259 return this; 260 } 261}