001/*- 002 * #%L 003 * HAPI FHIR JPA Server 004 * %% 005 * Copyright (C) 2014 - 2023 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.dao.JpaPid; 023import ca.uhn.fhir.jpa.model.entity.AuditableBasePartitionable; 024import ca.uhn.fhir.jpa.model.entity.ResourceTable; 025import ca.uhn.fhir.mdm.api.IMdmLink; 026import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum; 027import ca.uhn.fhir.mdm.api.MdmMatchResultEnum; 028import org.apache.commons.lang3.builder.ToStringBuilder; 029import org.hibernate.envers.AuditTable; 030import org.hibernate.envers.Audited; 031import org.hibernate.envers.NotAudited; 032 033import java.util.Date; 034import javax.persistence.Column; 035import javax.persistence.Entity; 036import javax.persistence.EnumType; 037import javax.persistence.Enumerated; 038import javax.persistence.FetchType; 039import javax.persistence.ForeignKey; 040import javax.persistence.GeneratedValue; 041import javax.persistence.GenerationType; 042import javax.persistence.Id; 043import javax.persistence.Index; 044import javax.persistence.JoinColumn; 045import javax.persistence.ManyToOne; 046import javax.persistence.SequenceGenerator; 047import javax.persistence.Table; 048import javax.persistence.Temporal; 049import javax.persistence.TemporalType; 050import javax.persistence.UniqueConstraint; 051 052@Entity 053@Table( 054 name = "MPI_LINK", 055 uniqueConstraints = { 056 // TODO GGG DROP this index, and instead use the below one 057 @UniqueConstraint( 058 name = "IDX_EMPI_PERSON_TGT", 059 columnNames = {"PERSON_PID", "TARGET_PID"}), 060 // TODO GGG Should i make individual indices for PERSON/TARGET? 061 }, 062 indexes = { 063 @Index(name = "IDX_EMPI_MATCH_TGT_VER", columnList = "MATCH_RESULT, TARGET_PID, VERSION"), 064 // v---- this one 065 @Index(name = "IDX_EMPI_GR_TGT", columnList = "GOLDEN_RESOURCE_PID, TARGET_PID"), 066 @Index(name = "FK_EMPI_LINK_TARGET", columnList = "TARGET_PID") 067 }) 068@Audited 069// This is the table name generated by default by envers, but we set it explicitly for clarity 070@AuditTable("MPI_LINK_AUD") 071public class MdmLink extends AuditableBasePartitionable implements IMdmLink<JpaPid> { 072 public static final int VERSION_LENGTH = 16; 073 private static final int MATCH_RESULT_LENGTH = 16; 074 private static final int LINK_SOURCE_LENGTH = 16; 075 public static final int SOURCE_TYPE_LENGTH = 40; 076 077 @SequenceGenerator(name = "SEQ_EMPI_LINK_ID", sequenceName = "SEQ_EMPI_LINK_ID") 078 @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_EMPI_LINK_ID") 079 @Id 080 @Column(name = "PID") 081 private Long myId; 082 083 @ManyToOne( 084 optional = false, 085 fetch = FetchType.LAZY, 086 cascade = {}) 087 @JoinColumn( 088 name = "GOLDEN_RESOURCE_PID", 089 referencedColumnName = "RES_ID", 090 foreignKey = @ForeignKey(name = "FK_EMPI_LINK_GOLDEN_RESOURCE"), 091 insertable = false, 092 updatable = false, 093 nullable = false) 094 @NotAudited 095 private ResourceTable myGoldenResource; 096 097 @Column(name = "GOLDEN_RESOURCE_PID", nullable = false) 098 private Long myGoldenResourcePid; 099 100 @Deprecated 101 @ManyToOne( 102 optional = false, 103 fetch = FetchType.LAZY, 104 cascade = {}) 105 @JoinColumn( 106 name = "PERSON_PID", 107 referencedColumnName = "RES_ID", 108 foreignKey = @ForeignKey(name = "FK_EMPI_LINK_PERSON"), 109 insertable = false, 110 updatable = false, 111 nullable = false) 112 @NotAudited 113 private ResourceTable myPerson; 114 115 @Deprecated 116 @Column(name = "PERSON_PID", nullable = false) 117 private Long myPersonPid; 118 119 @ManyToOne( 120 optional = false, 121 fetch = FetchType.LAZY, 122 cascade = {}) 123 @JoinColumn( 124 name = "TARGET_PID", 125 referencedColumnName = "RES_ID", 126 foreignKey = @ForeignKey(name = "FK_EMPI_LINK_TARGET"), 127 insertable = false, 128 updatable = false, 129 nullable = false) 130 @NotAudited 131 private ResourceTable mySource; 132 133 @Column(name = "TARGET_PID", updatable = false, nullable = false) 134 private Long mySourcePid; 135 136 @Column(name = "MATCH_RESULT", nullable = false) 137 @Enumerated(EnumType.ORDINAL) 138 private MdmMatchResultEnum myMatchResult; 139 140 @Column(name = "LINK_SOURCE", nullable = false) 141 @Enumerated(EnumType.ORDINAL) 142 private MdmLinkSourceEnum myLinkSource; 143 144 @Temporal(TemporalType.TIMESTAMP) 145 @Column(name = "CREATED", nullable = false) 146 private Date myCreated; 147 148 @Temporal(TemporalType.TIMESTAMP) 149 @Column(name = "UPDATED", nullable = false) 150 private Date myUpdated; 151 152 @Column(name = "VERSION", nullable = false, length = VERSION_LENGTH) 153 private String myVersion; 154 155 /** This link was created as a result of an eid match **/ 156 @Column(name = "EID_MATCH") 157 private Boolean myEidMatch; 158 159 /** This link created a new person **/ 160 @Column(name = "NEW_PERSON") 161 private Boolean myHadToCreateNewGoldenResource; 162 163 @Column(name = "VECTOR") 164 private Long myVector; 165 166 @Column(name = "SCORE") 167 private Double myScore; 168 169 // TODO GGG GL-1340 170 @Column(name = "RULE_COUNT") 171 private Long myRuleCount; 172 173 public MdmLink() {} 174 175 public MdmLink(String theVersion) { 176 myVersion = theVersion; 177 } 178 179 @Column(name = "TARGET_TYPE", nullable = true, length = SOURCE_TYPE_LENGTH) 180 private String myMdmSourceType; 181 182 @Override 183 public JpaPid getId() { 184 return JpaPid.fromId(myId); 185 } 186 187 @Override 188 public MdmLink setId(JpaPid theId) { 189 myId = theId.getId(); 190 return this; 191 } 192 193 @Override 194 public JpaPid getGoldenResourcePersistenceId() { 195 return JpaPid.fromId(myGoldenResourcePid); 196 } 197 198 @Override 199 public IMdmLink setGoldenResourcePersistenceId(JpaPid theGoldenResourcePid) { 200 Long longPid = theGoldenResourcePid.getId(); 201 setPersonPid(longPid); 202 203 myGoldenResourcePid = longPid; 204 return this; 205 } 206 207 @Override 208 public JpaPid getSourcePersistenceId() { 209 return JpaPid.fromId(mySourcePid); 210 } 211 212 @Override 213 public IMdmLink setSourcePersistenceId(JpaPid theSourcePid) { 214 mySourcePid = theSourcePid.getId(); 215 return this; 216 } 217 218 public ResourceTable getGoldenResource() { 219 return myGoldenResource; 220 } 221 222 public MdmLink setGoldenResource(ResourceTable theGoldenResource) { 223 myGoldenResource = theGoldenResource; 224 myGoldenResourcePid = theGoldenResource.getId(); 225 226 myPerson = theGoldenResource; 227 myPersonPid = theGoldenResource.getId(); 228 229 return this; 230 } 231 232 @Deprecated 233 public Long getGoldenResourcePid() { 234 return myGoldenResourcePid; 235 } 236 237 /** 238 * @deprecated Use {@link #setGoldenResourcePid(Long)} instead 239 */ 240 @Deprecated 241 public MdmLink setPersonPid(Long thePersonPid) { 242 myPersonPid = thePersonPid; 243 return this; 244 } 245 246 /** 247 * @deprecated Use {@link #setGoldenResourcePersistenceId(JpaPid)} instead 248 */ 249 @Deprecated 250 public MdmLink setGoldenResourcePid(Long theGoldenResourcePid) { 251 setPersonPid(theGoldenResourcePid); 252 253 myGoldenResourcePid = theGoldenResourcePid; 254 return this; 255 } 256 257 public ResourceTable getSource() { 258 return mySource; 259 } 260 261 public MdmLink setSource(ResourceTable theSource) { 262 mySource = theSource; 263 mySourcePid = theSource.getId(); 264 return this; 265 } 266 267 @Deprecated 268 public Long getSourcePid() { 269 return mySourcePid; 270 } 271 272 /** 273 * @deprecated Use {@link #setSourcePersistenceId(JpaPid)} instead 274 */ 275 @Deprecated 276 public MdmLink setSourcePid(Long theSourcePid) { 277 mySourcePid = theSourcePid; 278 return this; 279 } 280 281 @Override 282 public MdmMatchResultEnum getMatchResult() { 283 return myMatchResult; 284 } 285 286 @Override 287 public MdmLink setMatchResult(MdmMatchResultEnum theMatchResult) { 288 myMatchResult = theMatchResult; 289 return this; 290 } 291 292 @Override 293 public MdmLinkSourceEnum getLinkSource() { 294 return myLinkSource; 295 } 296 297 @Override 298 public MdmLink setLinkSource(MdmLinkSourceEnum theLinkSource) { 299 myLinkSource = theLinkSource; 300 return this; 301 } 302 303 @Override 304 public Date getCreated() { 305 return myCreated; 306 } 307 308 @Override 309 public MdmLink setCreated(Date theCreated) { 310 myCreated = theCreated; 311 return this; 312 } 313 314 @Override 315 public Date getUpdated() { 316 return myUpdated; 317 } 318 319 @Override 320 public MdmLink setUpdated(Date theUpdated) { 321 myUpdated = theUpdated; 322 return this; 323 } 324 325 @Override 326 public String getVersion() { 327 return myVersion; 328 } 329 330 @Override 331 public MdmLink setVersion(String theVersion) { 332 myVersion = theVersion; 333 return this; 334 } 335 336 @Override 337 public Long getVector() { 338 return myVector; 339 } 340 341 @Override 342 public MdmLink setVector(Long theVector) { 343 myVector = theVector; 344 return this; 345 } 346 347 @Override 348 public Double getScore() { 349 return myScore; 350 } 351 352 @Override 353 public MdmLink setScore(Double theScore) { 354 myScore = theScore; 355 return this; 356 } 357 358 public Boolean getEidMatch() { 359 return myEidMatch; 360 } 361 362 /** 363 * Note that this method can not be called <code>getEidMatch</code> or 364 * <code>isEidMatch</code> because Hibernate Search complains about having 365 * 2 accessors for this property 366 */ 367 @Override 368 public Boolean isEidMatchPresent() { 369 return myEidMatch != null && myEidMatch; 370 } 371 372 @Override 373 public MdmLink setEidMatch(Boolean theEidMatch) { 374 myEidMatch = theEidMatch; 375 return this; 376 } 377 378 @Override 379 public Boolean getHadToCreateNewGoldenResource() { 380 return myHadToCreateNewGoldenResource != null && myHadToCreateNewGoldenResource; 381 } 382 383 @Override 384 public MdmLink setHadToCreateNewGoldenResource(Boolean theHadToCreateNewResource) { 385 myHadToCreateNewGoldenResource = theHadToCreateNewResource; 386 return this; 387 } 388 389 public MdmLink setMdmSourceType(String mdmSourceType) { 390 myMdmSourceType = mdmSourceType; 391 return this; 392 } 393 394 @Override 395 public String toString() { 396 return new ToStringBuilder(this) 397 .append("myId", myId) 398 .append("myGoldenResource", myGoldenResourcePid) 399 .append("mySourcePid", mySourcePid) 400 .append("myMdmSourceType", myMdmSourceType) 401 .append("myMatchResult", myMatchResult) 402 .append("myLinkSource", myLinkSource) 403 .append("myEidMatch", myEidMatch) 404 .append("myHadToCreateNewResource", myHadToCreateNewGoldenResource) 405 .append("myScore", myScore) 406 .append("myRuleCount", myRuleCount) 407 .append("myPartitionId", getPartitionId()) 408 .toString(); 409 } 410 411 public String getMdmSourceType() { 412 return myMdmSourceType; 413 } 414 415 public Long getRuleCount() { 416 return myRuleCount; 417 } 418 419 public MdmLink setRuleCount(Long theRuleCount) { 420 myRuleCount = theRuleCount; 421 return this; 422 } 423}